martes, 10 de julio de 2012

Hashtables con hsearch_r y hcreate_r, hecho fácil


hsearch_r(), hcreate_r() y hdestroy_r() son funciones POSIX para el manejo de hashtables. No son las más intuitivas, ni tampoco las más portables, pero el hecho de que vengan con cualquier sistema GNU y no tengas que instalarlas las hace muy cómodas.

Dado que trabajar con ellas es poco práctico he creado unas macros que facilitan su uso y hacen el código más legible. Son las siguientes:


#define _GNU_SOURCE
#include <search.h>


#define HASHTABLE_CREATE(name, sz) \
   struct hsearch_data *name = calloc(sz, sizeof(struct htsearch_data*)); \
   hcreate_r(sz, name); 

#define HASHTABLE_DESTROY(name) hdestroy_r(name)

#define HASHTABLE_SET(name, strkey, value) \
{ \
   ENTRY e, *r; \
   e.key = strkey; \
   if(hsearch_r(e, FIND, &r, name)) \
   { \
      r->data = (void*) (value); \
   } \
   else \
   { \
      e.data = (void*) (value); \
      hsearch_r(e, ENTER, &r, name); \
   } \
}


#define HASHTABLE_GET(name, strkey, value) \
{ \
   ENTRY e, *r; \
   e.key = strkey; \
   if(hsearch_r(e, FIND, &r, name)) \
   { \
      value=(int)r->data; \
   } \
   else \
   { \
      value=(int)0; \
   } \
}


Pegando este código en el programa, se pueden usar fácilmente hashtables, como se muestra en el ejemplo:



   HASHTABLE_CREATE(ht, 100);

   HASHTABLE_SET(ht, "e1", 1);
   HASHTABLE_SET(ht, "e2", 2);
   HASHTABLE_SET(ht, "e3", 3);
   HASHTABLE_SET(ht, "e4", 4);
   HASHTABLE_SET(ht, "e5", 5);

   int i;
   HASHTABLE_GET(ht, "e1", i);
   printf("val: %d\n", i);
   HASHTABLE_GET(ht, "e2", i);
   printf("val: %d\n", i);
   HASHTABLE_GET(ht, "e3", i);
   printf("val: %d\n", i);
   HASHTABLE_GET(ht, "e4", i);
   printf("val: %d\n", i);

   HASHTABLE_DESTROY(ht);


Como se ve, el ejemplo es muy sencillo. Primero creamos una estructura con espacio para 100 elementos (caben más, pero habrá colisiones y no será óptimo). Después añadimos elementos, y posteriormente los consultamos. Finalmente, eliminamos la estructura.

A tener en cuenta que HASHTABLE_GET almacena el resultado en "i", lo cual puede confundir un poco al leer el código.

Las macros están hechas para trabajar con valores enteros, pero son fácilmente modificables.






jueves, 26 de enero de 2012

Sockets multiplataforma con GTK+

Recientemente hemos visto como realizar compilación cruzada con GTK+. Esto nos permite escribir aplicaciones que se ejecutan en diferentes plataformas, almenos a nivel gráfico.

Vamos a ver ahora como usar sockets TCP, algo que habitualmente suele estar muy ligado a una plataforma concreta. GTK+ (de hecho es GLIB) nos proporciona una API para acceder a la red. Esta API, al igual que GTK+ es multiplataforma.

Escribiremos un cliente TCP sencillo, que se conectará a un puerto, escribirá un mensaje, y leerá la respuesta.

Primero incluimos las cabeceras habituales en un programa C, junto con las cabeceras de GTK+.

#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>

Necesitamos las siguientes variables;

GError *err = NULL;
GSocket *sock = NULL;
GInetAddress *iaddr = NULL;
GSocketAddress *saddr = NULL;
GCancellable *cancel = NULL;

Usamos las siguientes funciones para inicializar las variables que contienen las direcciones de red. Lògicamente con la IP y puerto que convenga:

g_type_init();
iaddr = g_inet_address_new_from_string("192.168.1.1");
saddr = g_inet_socket_address_new(iaddr, 23);

Abrimos el socket y nos conectamos a el:

sock = g_socket_new(
   G_SOCKET_FAMILY_IPV4,
   G_SOCKET_TYPE_STREAM,
   G_SOCKET_PROTOCOL_TCP,
   &err);

f(!g_socket_connect(sock, saddr, cancel, &err))
{
   printf("Cannot connect\n");
   return -1;
}

Y finalmente, enviamos y recibimos datos:

   char buf[256];
   strncpy(buf, "lst\n", sizeof(buf));
   g_socket_send(sock, buf, strlen(buf), cancel, &err);
   g_socket_receive(sock, buf, sizeof(buf), cancel, &err);

   printf("received:\n%s\n", buf);


Sencillo, ¿no?


miércoles, 25 de enero de 2012

Sockets TCP con Bash

Es muy habitual, cuando se escriben scripts en Bash, recurrir a herramientas como "netcat" para realizar comunicaciones de red. Sin embargo, aunque no es muy conocido, Bash soporta sockets.

Veamos como conectarnos, por ejemplo, a google.
Abrimos el socket y le asociamos el descriptor 3. Recordemos que 0, 1 y 2 se usan habitualmente para la entrada y salida estándard y para la salida de error.

$ exec 3<>/dev/tcp/www.google.com/80

A continuación, enviamos un mensaje por el socket:

$ echo "GET /" >&3

Y finalmente, leemos la respuesta del servidor:

$ cat <&3

HTTP/1.0 302 Found
Location: http://www.google.es/
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Set-Cookie: PREF=ID=a38d7ed8770f70cb:FF=0:TM=1327418982:LM=1327418982:S=0tgHEV7GxJaC6Wl7; expires=Thu, 23-Jan-2014 15:29:42 GMT; path=/; domain=.google.com
Date: Tue, 24 Jan 2012 15:29:42 GMT
Server: gws
Content-Length: 218
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
... 


martes, 24 de enero de 2012

Compila en Linux y ejecuta en Windows con GTK+

Vamos a ver como realizar una compilación cruzada con las librerías de GTK+. Esto nos permitirá compilar el programa en Linux y ejecutarlo en Windows, por lo que podremos tener programas funcionando en Windows sin tener que usarlo.

Lo primero que tenemos que hacer es instalar el compilador mingw. En mi distribución vale con:

sudo apt-get install mingw32

A continuación tenemos que descargar las librerías necesarias de windows en nuestro Linux. Podemos encontrarlas en

$ wget http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28/glib-dev_2.28.8-1_win32.zip
$ wget http://ftp.gnome.org/pub/gnome/binaries/win32/atk/1.32/atk-dev_1.32.0-2_win32.zip
$ wget http://ftp.gnome.org/pub/gnome/binaries/win32/pango/1.29/pango-dev_1.29.4-1_win32.zip
$ wget http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/cairo-dev_1.10.2-2_win32.zip
$ wget http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/libpng-dev_1.4.3-1_win32.zip
$ wget http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime-dev_0.18.1.1-2_win32.zip
$ wget http://ftp.gnome.org/pub/gnome/binaries/win32/gtk+/2.24/gtk+-dev_2.24.8-1_win32.zip
$ wget http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/fontconfig-dev_2.8.0-2_win32.zip
$ wget http://ftp.gnome.org/pub/gnome/binaries/win32/gdk-pixbuf/2.24/gdk-pixbuf-dev_2.24.0-1_win32.zip

Descomprimiremos los zip dentro del directorio donde se instala mingw. Habitualmente:
/usr/i586-mingw32msvc/

Entramos en dicho directorio y realizamos algunos ajustes:

sed -i 's|^prefix=.*$|prefix=/usr/i586-mingw32msvc|g' lib/pkgconfig/*.pc
cd ./lib
for f in *.lib;
   do mv $f lib${f%%lib}a;
done

En mi caso faltaba un archivo en pkgconfig, lo he corregido con:

$ cp /usr/lib/i386-linux-gnu/pkgconfig/freetype2.pc  pkgconfig/

Pero podría estar ubicado en otro sitio en otras distros.

Llegados a este punto ya deberíamos poder compilar tanto para windows como para linux.

Si compilamos con el siguiente comando:

i586-mingw32msvc-gcc main.c `PKG_CONFIG_LIBDIR=/usr/i586-mingw32msvc/lib/pkgconfig PKG_CONFIG_PATH=/usr/i586-mingw32msvc/lib/pkgconfig pkg-config --cflags --libs gtk+-2.0`

generaremos un ejecutable para Windows. En este caso "a.exe".

Y si compilamos con este comando:

gcc main.c `pkg-config --cflags --libs gtk+-2.0 gmodule-export-2.0`

Obtendremos un ejecutable para Linux "a.out". Ya tenemos pues, nuestro sistema de compilación cruzada preparado.

Ya podemos trasladar nuestro ejecutable a Windows y probarlo. Para que funcione es necesario haber instalado GTK+ para Windows.

sábado, 21 de enero de 2012

Esteganografía LSB en imágenes bitmap

Uno de los métodos más populares de Esteganografía consiste en modificar el valor del bit menos significativo de cada píxel, el LSB (Least Significant Bit). En este artículo vemos como hacerlo en imágenes de tipo bitmap, es decir, aquellas que estan estructuradas como matrices de números donde cada número representa un píxel (eso solo es cierto en imágenes en escala de grises. En imágenes en color existen varias representaciones como la RGB donde cada píxel está representado por tres valores, correspondientes a la cantidad de color rojo, la cantidad de color verde y la cantidad de color azul).

El motivo de usar el LSB es que su alteración no sueles ser perceptible visualmente (a menos que la imagen sea muy baja resolución)

Inserción secuencial:

El método más sencillo consiste en separar los bytes que forman el mensaje en bits individuales. A continuación se recorren los píxeles de la imagen modificando su LSB de manera que quede igual que el del mensaje. Supongamos que queremos esconder un mensaje que empieza por 'H'. El valor en binario de la letra 'H' es 1001000. Por lo tanto tendremos que insertar:

1 0 0 1 0 0 0

Imaginemos ahora que los primeros 8 píxeles de la imagen corresponden a los bytes:

100 101 101 102 102 101 103

El primer píxel, correspondiente al valor 100 se representa en binario como 1100100. Dado que tenemos que modificar su LSB y ponerlo a uno, como el primer bit del mensaje, tendremos 1100101, que corresponde al valor de píxel 101. La operación es muy sencilla, si tenemos un valor de píxel par y queremos insertar un cero, no modificaremos el valor del píxel, pero si queremos insertar un uno, le sumaremos uno. Si por el contrario tenemos un píxel impar y queremos insertar un uno, no modificaremos su valor, pero si queremos insertar un cero, le restaremos uno.

Así, el primer byte queda como 101, el segundo como 100, el tercero como 100, etc

101 100 100 103 102 100 102

Para leer el mensaje solo tendremos que extraer los LSB de todos los píxeles.



Inserción aleatoria:

Insertar el mensaje de forma secuencial no es una forma muy acertada de hacerlo. Esto permite al atacante extraer el mensaje, por lo que, si no está cifrado, solo tiene que verificar que es legible (en una imagen sin mensaje oculto no lo sería).

Por este motivo es más aconsejable usar un generador pseudoaleatorio PRNG basado en una clave o contraseña, que eliga aleatoriamente los píxels en los que incrustar datos. De esta manera no bastaría con una simple extracción de todos los LSB.


Reducción del bitrate:

Aún y la enorme dificultad de conseguir el mensaje que ha sido ocultado usando un PRNG (necessitaríamos adivinar la contraseña), el objetivo de la esteganografía es hacer el mensaje indetectable, no indescifrable (de eso se encarga la criptografía). Por ello tenemos que intentar que la distribución estadística de los píxeles de la imagen se vea alterada lo menos posible. Si usamos bitrate 1, es decir, si modificamos todos los píxeles de la imagen, la distribución estadística se verá tan alterada que sermoes detectados sin demasiada dificultad. Por ello es conveniente reducir en la medida de lo posible el bitrate de inserción.

Los ataques existentes en la actualidad a los sistemas LSB son tan sofisticados que detectan alteraciones por encima de bitrates de 0,03. Es decir, que si no queremos ser detectados, deberíamos modificar como mucho el 3% de la imagen y hacerlo de forma aleatoria.



viernes, 20 de enero de 2012

Introducción a Arduino Ethernet: Hello World

Arduino es una plataforma de Hardware abierto cada vez más popular. Permite, de forma sencilla, realizar montajes electrónicos y programarlos. Recientemente ha aparecido en escena Arduino Ethernet, que a diferencia de los anteriores (Arduino Uno y Arduino Duemilanove, entre otros) tiene conexión RJ45 y soporte TCP/IP.



En este post vamos a realizar una breve introducción a Arduino Ethernet, viendo como dar los primeros pasos.

El programador:

A difernecia de los arduinos anteriores, que tenían una conexión USB que permitía cargar el firmware y depurar, el Arduino Ethernet solo tiene la conexión RJ45. Por ello es necesario usar el conector de la foto para programarlo:



Para poder usar este conector es necesario usar un programador. Existen multitud en el mercado. Por ejemplo este de Atmel.

Otra opción más económica consiste en usar el adaptador a USB.

El programa:

El programa más sencillo que se puede hacer con Arduino, y que nos muestre su funcionamiento, es hacer parpadear un led. Concretamente el led 13, que es el único que tiene. Seria el equivalente al típico "Hello World". El programa es el siguiente:

void setup()
{
   pinMode(13, OUTPUT);
}

void loop()
{
   digitalWrite(13, HIGH);
   delay(1000);
   digitalWrite(13, LOW);
   delay(1000);
}

El entorno  de Arduino llama a la función setup() al iniciar. Aprovechamos esta función para configurar el pin 13 como salida. La función loop() es llamada indefinidamente, por lo que en ella ponemos el cuerpo del programa. Lo que hacemos es encender el led, esperar un segundo, apagar el led y esperar de nuevo.

Cargar el firmware:

Una vez tenemos el programa podemos  cargarlo al Arduino de dos formas, en función de si disponemos del adaptador USB o del programador. 

En el primer caso podemos usar el software de Arduino.  Es la forma más sencilla, simplemente escribimos el programa en el entorno de programación y lo cargamos con la opción "Upload". 



Si queremos usar el programador, la forma más sencilla de hacerlo consiste en usar el entorno de programación de Arduino para compilar el programa y el programa avrdude para subir el firmware. Podemos hacerlo con el siguiente comando:

sudo avrdude -c avrispmkII -p m328p -u -U flash:w:firmware.hex -P usb

Donde firmware.hex es el archivo generado por el entorno de programación de Arduino.

Resultados:

Si todo ha funcionado como es debido, veremos como el led de la placa parpadea. Ya tenemos nuestro "Hello World"!


jueves, 19 de enero de 2012

Esteganografía moderna


La primera aparición de la Esteganografía en medios digitales la realizó G. J. Simmons  en 1983 [1]. En el se habla de las posibles implicaciones políticas de enviar datos a través de canales encubiertos y se plantea el problema del prisionero.

El problema del prisionero: 

Alice y Bob son encarcelados en celdas separadas. Pueden comunicarse y quieren planear una fuga, pero sus mensajes son monitorizados por el carcelero Eve. Si Eve descubre que Alice y Bob están intercambiando mensajes secretos no dejará que vuelvan a comunicarse. Por ello, Alice y Bob recurren a la Esteganografía para comunicarse.

En el problema el prisionero hay que destacar que Eve cortará la comunicación si detecta que Alice y Bob se comunican de manera secreta. No es necesario que Eve tenga acceso al mensaje, sólo que lo detecte. Así, un sistema de Esteganografía se considerará roto si puede ser detectada la existencia de un mensaje. No es necesario acceder a su contenido, esto formaría parte del Estegoanálsisis forense (extracción del mensaje) y del criptoanálisis (descifrado del mensaje).


En el problema del prisionero se asume que Eve conoce el algoritmo usado para esconder los datos pero no la clave. Este es un requisito tomado de la Criptografía, que forma parte de los conocidos Principios de Kerchhoff

Referencias: 

[1] G. J. Simmons. The prisoner's problem and the subliminal channel. D. Chaum editor, advances in Criptology, CRYPTO '83, pages 51-67, Santa Barbara, CA, August 22-24, 1983. New York: Plenum Press.