Skip to main content

Un wallpaper nuevo cada día (con CFDG)

Trasteando con CFDG, por decirlo así, el "padre" en 2D de Structure_Synth, y tras comprobar que tiene la misma capacidad que su versión en 3D de generar gráficos aleatorios "interesantes", y que el fondo de pantalla ya lleva un buen tiempo siendo el mismo, ¿que mejor que hacer que este lo genere un programa, haciendo que sea nuevo cada vez? :D

La idea es bastante simple, hacer un script que llame a CFDG sobre un código hecho antes cada vez que se quiera (que el usuario se loguee o cada cierto tiempo aprovechando cron).

El script en sí es bastante sencillo, algo así lo haría perfectamente

!/usr/bin/env bash

wide=1280

high=800

cfdg back.cfdg -oback.png -w $wide -h $high &

Por supuesto, habría que cambiar wide por el ancho de la pantalla y high por su alto, para generar una imágen óptima.

El resto no es más dificil, hacer un archivo de CFDG, este por ejemplo genera espirales que parecen hechas con rotulador (¿?) , es grande para incluir más variaciones:

===============================================================================

startshape init

rule init{ dot { saturation 1} }

// Dot made rule dot 0.01 { SQUARE { } dot { s 0.995 rotate 1 x 1 hue -1  } }

rule dot  { SQUARE { } dot { s 0.995 rotate -1 x 1 hue 1 } }

rule dot 0.9 { SQUARE { } dot { s 1.005 rotate 1 x - 1} }

/*// Comment this for removing color rule init 1000{ dot { saturation 1 brightness 0.9 } }

rule dot 0.01{ dot { brightness 0.90 } }

rule dot 0.01{ dot { brightness 0 } }

rule dot 0.01{ dot { brightness 0.4 } }

rule dot 0.005{ dot { hue 180 }

} //*/

===============================================================================

(El /* se puede eliminar para tener algo de colorido, para gustos...) Y la imagen resultante de ejecutar el script se utiliza de fondo de pantalla, el resultado podría ser algo así en este caso:

Aunque claro, la gracia está en el cambio. Cómo hacer que se ejecute el script es cosa de cada uno, la forma más facil en las distribuciones con gnome (para Xfce, KDE lo mismo) es a través de Sistema > Preferencias > Aplicaciones al inicio, aunque (como ya se dijo antés), cron puede ser una opción interesante para que se renueve incluso cuando no se hace logout.

Hasta otra.

ps: La instalación de CFDG no tiene ningún misterio, se descomprime, se hace make para compilar y sudo cp cfdg /usr/bin/ para instalar.

[Referencias] CFDG_HowTo

Hablando por el terminal

Hoy traigo algo medio OffTopic, para pasar el rato.

Un intérprete de comandos ya permite pasarse horas programando cosas más o menos útiles, pero si además le añadimos un sintetizador de voz, las posibilidades solo las limita la imaginación.

eSpeak es un programa (disponible a través del paquete correspondiente) que permite usar un sintetizador de voz por línea de comandos (aunque tambien tiene una gui), la entrada por defecto se hace por stdin, así que utilizando tuberías (pipes) se pueden hacer cosas bastante curiosas, el parámetro más a tener en cuenta es la voz (que regulará la pronunciación), por defecto es el inglés, pero con -ves se puede configurar para castellano, la sintaxis, es -v [código del idioma]

Algunos ejemplos de su uso pueden ser

=============================================================================== fortune | espeak -ves ===============================================================================

para que lea una frase aleatoria

o

=============================================================================== i=1 while [ $i -le 10 ]     do     j=1     while [ $j -le 10 ]         do         r=$(( $i * $j))         echo "$i por $j es = a $r"         j=$(($j + 1))     done     i=$(($i + 1)) done|espeak -ves ===============================================================================

o en una línea

=============================================================================== i=1;while [ $i -le 10 ]; do j=1; while [ $j -le 10 ]; do r=$(( $i * $j)); echo "$i por $j es = a $r"; j=$(($j + 1)); done; i=$(($i + 1)); done|espeak -ves ===============================================================================

para que diga la tabla del 1 al 10

El resto es cuestión de imaginación, combinado con un poco de scripting puede servir para que avise cuando la temperatura del PC sube demasiado, cuando llegue una hora preconfigurada (típica alarma)  o cuando alguien está hablando con nosotros por el IRC... lo difícil es encontrar algo para lo que sea realmente necesario :)

Hasta otra.

[Referencias] http://espeak.sourceforge.net/

Pensando en paralelo

Edit (3 meses despues...): Que fallo mas tonto!, me olvide de colgar la implementación de la lista enlazada :(, está aquí [llist.c]

Entre los paradigmas de programacion en paralelo, destacan el multiproceso (varios procesos, un hilo para cada uno), y el multihilo (un solo proceso, varios hilos de ejecucion), la principal diferencia es que si un programa es multiproceso, la memoria (la RAM) no es compartida, esto hace que no haya que preocuparse de cuando se accede a los datos, o se modifican, para evitar que otras instancias del programa fallen, pero hace obligatorio el uso de IPC (Comunicacion Entre Procesos) para coordinar el programa.

Asi, con el multihilo el IPC se puede reemplazar por cosas como variables globales, ademas por no necesitar una region de memoria propia, es bastante mas ligero, aun asi, elijas el modelo que elijas, siempre tendras el mismo problema, que se puede resumir en

-¿Por que cruzo la gallina paralela la calle?  
-cruzar la calle Para

-¿Por que cruzo la gallina paralela la calle?  
-Para calle la cruzar

Que se quiere decir con esto?, que la programacion en paralelo implica que mucho codigo se va a invertir en coordinar el programa... y bueno, a quien le guste esa parte, pues bien, pero a quien no...

Esta presentacion tan... cutre , era para mostrar un pequeño codigo (aunque aun esta bastante verde) que pretende simplificar el uso de programas multihilo sobre listas de palabras, por ejemplo:

include "thread_launcher.h"

include

include

void print(char *s){

printf("%s\n",s); }

int main(int argc,char **argv){

if (argc<2){         printf("Uso: ./sample \n");

return 1;     }     FILE *f=fopen(argv[1],"r");

if (f==NULL){         printf("No se ha podido leer el archivo %s\n",argv[1]);

return 2;     }     launch_threads(2, print, f);

fclose(f);     return 0; }

Lo unico que hay que hacer (aparte de añadir -lpthread al compilar y importar el codigo), es abrir un archivo, y usar la funcion:

launch_threads(, , );

[ThreadLauncher.zip]

ps: el codigo esta acabado, pero no demasiado probado... aviso...

Hasta otra!

[How to] OpenSSL en C/C++

Pues como parece que la documentacion de OpenSSL no es precisamente la mejor he pensado en hacer una guia rapida, aqui la teneis.

Pero, antes de empezar, que es OpenSSL ? OpenSSL es una implementacion libre (bajo una licencia apache-like) de los protocolos SSL y TLS. Implementa las funciones basicas de criptografia y provee varias funciones utiles.

Instalacion: Esto no tiene gran misterio, instala libssl-dev desde tu repositorio de paquetes y ya está. * Hola mundo ***

Las librerias que se van a utilizar son:

* openssl/bio.h

* openssl/ssl.h
*
* openssl/err.h
*

El hola mundo sería algo asi:

include

// Cabeceras OpenSSL

include

include

include

int main(int argc,char ** argv){

// Iniciando OpenSSL

SSL_load_error_strings();

ERR_load_BIO_strings();

OpenSSL_add_all_algorithms();

printf("Hola, mundo de OpenSSL\n");

return 0;

}

Hay que linkarlo con libssl (por ejemplo, compilando con el comando gcc helloworld.c -lssl -o hello_world

). El resultado es bastante obvio: Hola, mundo de OpenSSL

No, no hace nada util, pero si compilo bien, se puede seguir tranquilamente... sino,(logicamente) hay un problema.

Seguimos... * Conexiones inseguras ***

(es bastante parecido a unos sockets normales, pero sirve para familiarizarse con los conceptos):

El equivalente al int ; es BIO * ;, esto almacenara los datos de la conexion.

La funcion para crear una nueva conexion es esta: = BIO_new_connect("hostname:port");

Como se puede ver, la sintaxis es bastante sencilla y no requiere montar estructuras para establecer conexiones. Si la variable devuelta es NULL es que hubo un error creando el objeto BIO. Para comprobar que la conexion se ha establecido se utiliza esta función, si el valor devuelto es 0 o menor, no se ha podido conectar al host. BIO_do_connect();

Enviar y recibir datos se hace exactamente igual que con los sockets de BSD: -Para recibir: BIO_read(, , );

(Para quien lo dude, el buffer es donde se leera la informacion, y debe ser un puntero (o un array), las otras variables son obvias ;) El valor devuelto es el numero de bytes que se han leido, es posible que se necesite meter esta funcion en un bucle para asegurarse de que se leen todos los datos... aunque no suele haber problemas para buffer's de menos de 1Kb

-Para enviar es lo mismo: BIO_write(, , );

El valor devuelto es (de nuevo) el numero de bytes enviados, sin problemas para menos de 1Kb, aun asi mejor con un bucle... ya cojeis la idea, ¿no?

Para determinar si se puede leer/escribir (enviar/recibir) en una conexion, la funcion es: BIO_should_retry();

Si no se puede, el valor devuelto es false ,de todas formas, en las pruebas, esta funcion causo algunos problemas (¿quiza al tratar con sockets de lectura bloqueantes?), si quieres mas informacion [ http://www.openssl.org/ docs/crypto/BIO_should_retry.html ]

Un bucle simple (como este), solucionaria los posibles problemas: int sendloop(BIO * bio,char *buf,int buflen){

int pos=0,aux;

while (((aux=BIO_write(bio,buf+pos,buflen-pos))<1)&&(pos>0)){

   pos+=aux;

   if (!BIO_should_retry(bio)){

       return 0;

   }

}

return 1;

}

Para cerrar la conexion, simplemente hacemos: BIO_reset();

Y para liberar la memoria: BIO_free_all();

Esto seria un ejemplo de cliente HTTP, con OpenSSL (se muestran las cabeceras y la pagina en si, esto se puede cambiar, pero la idea era mostrar como funcionan las conexiones):

include

include

// Cabeceras de OpenSSL

include

include

include

// Bucle para enviar datos

int sendloop(BIO * bio,char *buf,int buflen){

int pos=0,aux;

while (((aux=BIO_write(bio,buf+pos,buflen-pos))<1)&&(pos>0)){

   pos+=aux;

   if (!BIO_should_retry(bio)){

       return 0;

   }

}

return 1;

}

int main(int argc,char ** argv){

// Comprueba que los parametros son los correctos (sin interes)

if (argc!=3){

   printf("Uso: ./conexion <hostname> <port>\n");

   exit(1);

}

char host_port[256];

sprintf(host_port,"%s:%s",argv[1],argv[2]);

BIO * bio;

// Se crea una nueva conexion

bio = BIO_new_connect(host_port);

if(bio == NULL){

   printf("Error en BIO_new_connect\n");

}

// Se comprueba que la conexion se establecio correctamente

if(BIO_do_connect(bio) <= 0){

   printf("Error al establecer conexion\n");

}

int i;

char buf[512];

// Se introduce las cabeceras HTTP en un buffer

sprintf(buf,"GET / HTTP/1.0\r\nHOST: %s\r\n\r\n",argv[1]);

// Y se envian

if ((i=sendloop(bio,buf,strlen(buf)))==0){

   printf("Error al enviar cabeceras\n");

   exit(0);

}

char ch_buf[2];

// Para todos los bytes que se reciben

while ((i=BIO_read(bio,&ch_buf,1))!=0){

   if (i>0){

   // Se muestran por pantalla

       putchar(ch_buf[0]);



   }

}

// La conexion ha finalizado

printf("\nConexion finalizada\n");

// Se cierra la conexion

BIO_reset(bio);

// Y se libera el espacio

BIO_free_all(bio);

}

* Conexiones seguras ***

Las conexiones seguras funcionan igual que las otras, la unica diferencia es en el momento de establecer la conexion... Ademas de BIO * bio;, se utilizan los siguientes objetos: SSL_CTX * ctx;

SSL * ssl;

Despues, hay que cargar las librerias, esto se hace con SSL_library_init ();

ERR_load_BIO_strings();

SSL_load_error_strings();

OpenSSL_add_all_algorithms();

(Esto solo hay que hacerlo una vez en todo el programa) El siguente paso, es crear un entorno SSL (SSL_CTX), que asignaremos a la variable ctx, esto se hace con las funciones SSL_CTX_new()  y SSLv_method (), pasando como parametro de la primera, la salida de la segunda. Pongo SSLv_method, por que hay varias opciones, segun el protocolo que se utilizara, ademas cada opcion se puede utilizar para clientes (SSLv_client_method), para servidores(SSLv_server_method), o para los dos (SSLv_method), para abreviar, se hablara solo de los que funcionan para ambas cosas, si prefieres una en concreto solo tienes que cambiar el nombre de la funcion(añadiendo _client o _server)...

* SSLv2_method(): Para utilizar unicamente SSLv2 en todo el proceso

* SSLv3_method(): Para utilizar unicamente SSLv3, esto puede producir
problemas porque en las versiones que soportan varios protocolos, la
conexion se suele iniciar con SSLv2

* TLSv1_method(): Para utilizar solo TLSv1, con los mismos problemas de
incompatibilidad que SSLv3_method()
*
* SSLv23_method(): Para utilizar SSLv2, SSLv3 o TLS1, segun lo que soporte
el otro extremos de la conexion, la conexion se iniciara como una de
SSLv2 (esta es obviamente la opcion que se deberia usar a menos que haya
razones para lo contrario)
*

Entonces, para iniciar el entorno, utilizamos: ctx=SSL_CTX_new(SSLv23_client_method());

Despues hay que cargar la lista de certificados fiables (al final dejo un archivo de prueba), esto se puede hacer desde un archivo o desde una carpeta, con: SSL_CTX_load_verify_locations(, , )

Si el valor devuelto es false, es que algo fue mal.

Logicamente, no es necesario hacerlo de las dos formas, el valor que no se utilice se reemplaza por NULL, esto es lo que utilice para cargar los certificados desde un archivo: if(! SSL_CTX_load_verify_locations(ctx, trust_store_file, NULL)){

printf("Error cargando certificados fiables\n");

SSL_CTX_free(ctx);

exit(0);

}

Otra cosa, si vas a importar los certificados desde una carpeta, primero hay que prepararla para este proposito, esto se puede hacer simplemente con: c_rehash /ruta/a/la/carpeta

El proximo paso es preparar los BIO y SSL: bio = BIO_new_ssl_connect(ctx);

BIO_get_ssl(bio, & ssl);

SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

Una vez hecho esto, hay que establecer la conexion, como se hace con las conexiones normales: BIO_set_conn_hostname(bio, host_port);

De nuevo, igual que en las conexiones normales, se comprueba que la conexion fue bien: if(BIO_do_connect(bio) <= 0){

printf("Error al establecer la conexion\n");

}

Por ultimo, solo queda comprobar que el certificado es correcto, en caso de que no lo sea, queda en manos del programador cerrar la conexion o continuarla: if(SSL_get_verify_result(ssl) != X509_V_OK){

// No, no es valido :(

// Pero, se puede continuar con la conexion, preguntemos al usuario

char op;

printf("El certificado no es valido, quieres continuar con la conexion(S/ n)");

op=getchar();

if (op=='n'){

   SSL_CTX_free(ctx);

   exit(1);

}

}

El resto de la conexion se utiliza como una normal.

Al final, cuando se acabe de utilizar ese entorno ssl, hacemos: SSL_CTX_free(ctx);

Este seria el ejemplo anterior del cliente HTTP, pero funcionando sobre SSL (recuerda que el puerto de HTTPS es 443):

include

include

// Cabeceras de OpenSSL

include

include

include

// Constantes

define trust_store_path "TrustStore/"

define trust_store_file "TrustStore.pem"

// Bucle para enviar datos

int sendloop(BIO * bio,char *buf,int buflen){

int pos=0,aux;

while (((aux=BIO_write(bio,buf+pos,buflen-pos))<1)&&(pos>0)){

   pos+=aux;

   if (!BIO_should_retry(bio)){

       return 0;

   }

}

return 1;

}

int main(int argc,char ** argv){

// Comprueba que los parametros son los correctos (sin interes)

if (argc!=3){

   printf("Uso: ./conexion <hostname> <port>\n");

   exit(1);

}

char host_port[256];

sprintf(host_port,"%s:%s",argv[1],argv[2]);

// Se preparan los objetos

SSL_CTX * ctx;

SSL * ssl;

BIO * bio;

// Y se levanta la libreria

SSL_library_init ();

ERR_load_BIO_strings();

SSL_load_error_strings();

OpenSSL_add_all_algorithms();

ctx=SSL_CTX_new(SSLv23_method());

// Se carga la lista de certificados fiables desde un archivo

if(! SSL_CTX_load_verify_locations(ctx, trust_store_file, NULL)){

   printf("Error cargando certificados fiables\n");

   SSL_CTX_free(ctx);

   exit(0);

}

/*

// Se carga la lista de certificados fiables desde una carpeta

// Antes hay que usar este comando:

// c_rehash /ruta/a/la/carpeta

//

if(! SSL_CTX_load_verify_locations(ctx, NULL, trust_store_path)){

   printf("Error al cargar la lista de certificados fiables\n");

   exit(1);

}

*/

// Configuramos el BIO y el SSL

bio = BIO_new_ssl_connect(ctx);

BIO_get_ssl(bio, & ssl);

SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

// Se establece la conexion

BIO_set_conn_hostname(bio, host_port);

// Se comprueba la conexion y se realiza el "apreton de manos"

if(BIO_do_connect(bio) <= 0){

   printf("Error al establecer la conexion\n");

   SSL_CTX_free(ctx);

   exit(1);

}

// Se comprueba que el certificado es valido

if(SSL_get_verify_result(ssl) != X509_V_OK){

   // No, no es valido :(

   // Pero, se puede continuar con la conexion, preguntemos al usuario

   char op;

   printf("El certificado no es valido, quieres continuar con la conexion

(S/n)");

   op=getchar();



   if (op=='n'){

       SSL_CTX_free(ctx);

       exit(1);

   }

}

int i;

char buf[512];

// Se introduce las cabeceras HTTP en un buffer

sprintf(buf,"GET / HTTP/1.0\r\nHOST: %s\r\n\r\n",argv[1]);

// Y se envian

if ((i=sendloop(bio,buf,strlen(buf)))==0){

   printf("Error al enviar cabeceras\n");

   SSL_CTX_free(ctx);

   exit(0);

}

char ch_buf[2];

// Para todos los bytes que se reciben

while ((i=BIO_read(bio,&ch_buf,1))!=0){

   if (i>0){

       // Se muestran por pantalla

       putchar(ch_buf[0]);

   }

}

// La conexion ha finalizado

printf("\nConexion finalizada\n");

// Se cierra la conexion

BIO_reset(bio);

// Y se libera el espacio

BIO_free_all(bio);

// Limpiamos los datos del SSL

SSL_CTX_free(ctx);

}

* Funciones de criptografia ***

La idea no es mostrarlas todas, sino mostrar un par de ejemplos, el resto lo podeis buscar a traves de man o en http://www.openssl.org/docs/crypto/ crypto.html

SHA-1 (funcion hash)

Para hacer el hash SHA-1 de un string, la libreria utilizada es: openssl/sha.h

El uso es bastante sencillo,se utilizan 3 variables:

* El array que se hasheara

* La longitud del array
*
* El buffer donde se guardara la salida
*

Ahi va el codigo:

include

include

include

int main(int argc,char **argv){

if (argc<2){

   printf("Uso: ./sha1 <palabra> [<palabra>] [<palabra>]\n");

}

int i;

for (i=1;i<argc;i++){

   // Hasta aqui, nada interesante, viene ahora

   int digest[5];

   // Obtenemos la salida y la mostramos

   SHA1(argv[i],strlen(argv[i]),(char *)digest);



   printf("[%s] -> ",argv[i]);

   int j;



   for (j=0;j<5;j++){

       printf("%x",digest[j]);

   }

   putchar('\n');

}

}

* RC4 ***

(cifrado simetrico): La libreria utilizada es openssl/rc4.h

Para iniciar un cifrado, hay que crear la clave, esto se hace con RC4_set_key(<&key>,,);

Despues, solo hay que pasar los datos por RC4(<&key>,,,);

Por ejemplo:

include

include

include

define buff_len 256

void write_all(FILE f,void buf,size_t n){

int pos=0,tmp;

while (((tmp=fwrite(buf+pos,sizeof(char),n-pos,f))>0)&&(pos<n)){

   pos+=tmp;

}

}

int main(int argc,char **argv){

if (argc<4){

   printf("Uso: ./rc4 <contraseña> <archivo de entrada> <archivo de

salida>\n");

   exit(1);

}

FILE fin,fout;

fin=fopen(argv[2],"r");

if (fin==NULL){

   printf("El archivo de entrada esta vacio\n");

   exit(1);

}

fout=fopen(argv[3],"a");

if (fout==NULL){

   printf("Error al crear el archivo de salida\n");

   exit(1);

}

RC4_KEY key;

RC4_set_key(&key,strlen(argv[1]),argv[1]);

int l;

char buffer[buff_len];

char buffer_out[buff_len];

while ((l=fread(buffer,sizeof(char),buff_len,fin))>0){

   RC4(&amp;key,l,buffer,buffer_out);

   write_all(fout,buffer_out,l);

}

fclose(fin);

fclose(fout);

return 0;

}

Aqui teneis en ZIP con todos los archivos: [openssl_how_to.zip]

[Referencias] http://www.ibm.com/developerworks/views/linux/ libraryview.jsp?search_by=openssl&type_by=Articles http://www.openssl.org/docs/crypto/crypto.html

Esteganografia en python: modulo de BMP acabado

Pues nada, el modulo de bmp esta acabado, es decir, soporta:
* BMP de 24 Bits (8R,8G,8B)
* BMP de 32 Bits (8R,8G,8B,8X), sin compresion
* BMP de 32 Bits (8R,8G,8B,8X), con compresion (bit field) No esta previsto añadir cosas, pues eso es lo mas que soporta BMP,  las imagenes con menor profundidad ya ni se considera soportarlas, porque la esteganografia seria muy evidente.

pyStego_bmp01.zip

Lo proximo sera añadir soporte para GIF,JPEG o PNG (y APNG?) y soportar todos estos formatos antes de pasar a otro de datos (audio o video)

Hasta ahora!

plowshare, compartiendo archivos en Gnu/Linux

Plowshare es un downloader/uploader en línea de comandos (si esto es un problema para alguien, lo solucionamos ahora  ;) para algunas de las paginas de comparticion de archivos. Funciona en los sistemas Gnu/Linux, BSD, Mac OS X (con algunos parches) y windows (utilizando Cygwin)

Instalacion:      Archlinux: yaourt -Sy plowshare      Gentoo: emerge -av plowshare

Debian/Ubuntu: Hay que instalarlo a mano, para esto hacemos sudo apt-get install curl recode imagemagick tesseract-ocr-eng spidermonkey-bin aview  perlmagick gocr wget http://plowshare.googlecode.com/files/plowshare_0.9.2-1_all.deb sudo dpkg -i plowshare_0.9.2-1_all.deb

Comandos (repito, si prefieres, tienes mas abajo el codigo para hacer un interfaz) :  Para subir un archivo:

plowup [<-a|-b> ':'] [-d ] servidor Los parametros son: -a|-b: para subir utilizando un usuario, se usa -a en Megaupload o si es premium en Rapidshare y -b si es gratuito en Rapidshare. -d: Descripcion del archivo (acaso necesita explicacion). servidor: Servidor al que se subira (megaupload,rapidshare,zshare...)

Para bajar un archivo son bastante parecidos: plowdown [-a ':'] [-r ] Parametros:

-a: igual que para subir (aqui no existe -b). -r: velocidad maxima de descarga en Bytes/Segundo (con k para Kb,m para Kb y g para Gb). url: Direccion de donde descargar.

Interfaz hecha con tkInter:

[Referencias] http://code.google.com/p/plowshare http://code.google.com/p/plowshare/wiki/Readme

Esteganografia en python

Llevo bastante tiempo dandole vueltas a la idea de hacer una libreria de esteganografia en python, para poder usarla como base para una aplicacion completa... pues me he decidido a empezar, y estos son los primeros resultados:

baseops.py

bmp.py

El primero es simplemente un conjunto de funciones que creo que pueden ser de utilidad en los distintos modulos (extraer el LSB de un byte, descomponer un char en bits, leer un numero de un archivo...)

El segundo es lo que va comenzando a ser el modulo de esteganografia con BMP, por ahora esta bastante limitado, solo soporta imagenes de al menos 24bits de profundidad (esto seguramente no cambie, pues aceptar profundidades menores solo hace que la implementacion no sea tan sencilla, añadiendo una utilidad minima). Ademas, por ahora no soporta ningun tipo de compresion, aunque la idea seria implementar compresion/descompresion usando Bit Field (que se utiliza en imagenes de 32 bits)

La clase que se utilizaria es stego_bmp, inicializandose con el nombre del archivo del bmp base o a analizar, las funciones son:

bmp.addmsg(mensaje[,profundidad_utilizada]) # Añade un string a la imagen bmp.addfile(archivo[,profundidad_utilizada]) # Añade un archivo a la imagen

bmp.getmsg([profundidad_utilizada]) # Recupera un string a la imagen bmp.getfile(archivo[,profundidad_utilizada]) # Recupera un archivo de la imagen

bmp.dump(mensaje) # Guarda la imagen

Y por supuesto, todo esta bajo la GPLv3 =)

Por ultimo avisar que esto no utiliza ningun tipo de estructura, al recuperar un mensaje o un archivo seguramente obtengais una ristra de bytes extraños al final de el... esto es normal, la idea es hacer que sea versatil, si quieres asegurarte de cuales son los extremos de tu mensaje puedes utilizar algun tipo de caracter especial, se podria utilizar el caracter nulo ('\0') como en C, por ejemplo.

Hasta otra!

Actualizando el Jamendo OGG redirector

Pues resulta que el script de greasemonkey que se encargaba de redirigir las descargas de MP3 a las OGG funcionaba... pero solo si se estaba utilizando noScript, cosa que no tuve en cuenta (perdon) :P

Ya esta el codigo arreglado (solo hubo que añadir un substr() y listo), y funciona usando noScript o no ;)

Podeis descargarlo [aqui]

Y aqui esta el codigo_fuente (para quien no le apetezca buscarlo por la pagina)

Y ya esta, perdon por las molestias

Introduccion a la criptografia, con Python: MD5 (III)

Siguendo con el tema, en esta parte veremos como funciona la funcion de hash MD5:

¿Que es una funcion HASH?
En informática, Hash se refiere a una función o método para
generar claves o llaves que representen de manera casi unívoca a un
documento, registro, archivo, etc., resumir o identificar un dato a
través de la probabilidad, utilizando una función hash o algoritmo
hash. Un hash es el resultado de dicha función o algoritmo.
[Wikipedia]

Es decir, es una funcion de un solo sentido (a partir del resultado no se puede recuperar el original) que identifica un "objeto" con precision, si cambia un byte, cambia todo el resultado.

Esto se suele utilizar (por ejemplo) para comprobar que las descargas se realizaron correctamente, comparando el hash del archivo original y el del archivo descargado, si son iguales, todo fue bien :)

MD5 es una funcion de hash, pero presenta debilidades, como colisiones, por eso se deberia evitar usar en el futuro, de todas formas, aun se utiliza y servira de introduccion para este tipo de funciones. Vamos alla... class md5:

# Punto de inicio

def init(self,s):

   ln=len(s)*8

   self.padd(s)

   self.attach_len(ln)

   self.buff_init()

   self.update(ln)

   self.final()

El primer paso es añadir un bit '1' a lo que se quere hashear, y despues añadir '0's hasta que el tamaño en bits sea igual a 448, siendo modulo 512 (o 56, modulo 64, en bytes):
def padd(self,s):

   self.stream=s+"\x80"

   while ((len(self.stream)%64)!=56):

       self.stream+="\x00"

Despues hay que añadir a continuacion el tamaño en bits (al principio, antes del paso anterior) del archivo/mensaje/etc..., con un numero de 64 bits(8 bytes):
def attach_len(self,ln):

   ln%=1<<64

   i=7

   l=[]

   while i>=0:

       k=256**i

       aux=ln/k

       l.append(aux)

       ln-=aux*(k)

       i-=1

   while len(l)>0:

       self.stream+=chr(l.pop(len(l)-1))

Se inicializan cuatro buffers (A,B,C y D) (de 32 bits) que se utilizan en el algoritmo:
def buff_init(self):

   self.a = 0x67452301

   self.b = 0xefcdab89

   self.c = 0x98badcfe

   self.d = 0x10325476

Se procesa el  objeto/archivo/..., esto es la parte mas "opaca" del algoritmo... Para comenzar se divide el objeto en partes de 64 bytes, concretamente en arrays de 16 elementos, con 4 bytes cada uno:
def update(self,ln):

   i=0

   while i<(len(self.stream)/64):

       j=0

       x=[]

       while j<16:

           t=((ord(self.stream[(i*64)+(j*4)+0]))|

              (ord(self.stream[(i*64)+(j*4)+1])<< 8)|

              (ord(self.stream[(i*64)+(j*4)+2])<< 16)|

              (ord(self.stream[(i*64)+(j*4)+3])<< 24))

           x.append(t)

           j+=1

       self.transform(x)



       i+=1

Despues, con cada division se obtienen los valores de los buffer's:
def transform(self,x):

   AA=self.a

   BB=self.b

   CC=self.c

   DD=self.d

Y se le aplican una serie de transformaciones (veremos despues en detalle como funcionan esas transformaciones):
#Ronda 1

   AA=FF (AA, BB, CC, DD, x[ 0], S11, 0xd76aa478) # 1

   DD=FF (DD, AA, BB, CC, x[ 1], S12, 0xe8c7b756) # 2

   CC=FF (CC, DD, AA, BB, x[ 2], S13, 0x242070db) # 3

   BB=FF (BB, CC, DD, AA, x[ 3], S14, 0xc1bdceee) # 4

   AA=FF (AA, BB, CC, DD, x[ 4], S11, 0xf57c0faf) # 5

   DD=FF (DD, AA, BB, CC, x[ 5], S12, 0x4787c62a) # 6

   CC=FF (CC, DD, AA, BB, x[ 6], S13, 0xa8304613) # 7

   BB=FF (BB, CC, DD, AA, x[ 7], S14, 0xfd469501) # 8

   AA=FF (AA, BB, CC, DD, x[ 8], S11, 0x698098d8) # 9

   DD=FF (DD, AA, BB, CC, x[ 9], S12, 0x8b44f7af) # 10

   CC=FF (CC, DD, AA, BB, x[10], S13, 0xffff5bb1) # 11

   BB=FF (BB, CC, DD, AA, x[11], S14, 0x895cd7be) # 12

   AA=FF (AA, BB, CC, DD, x[12], S11, 0x6b901122) # 13

   DD=FF (DD, AA, BB, CC, x[13], S12, 0xfd987193) # 14

   CC=FF (CC, DD, AA, BB, x[14], S13, 0xa679438e) # 15

   BB=FF (BB, CC, DD, AA, x[15], S14, 0x49b40821) # 16



   # Round 2

   AA=GG (AA, BB, CC, DD, x[ 1], S21, 0xf61e2562) # 17

   DD=GG (DD, AA, BB, CC, x[ 6], S22, 0xc040b340) # 18

   CC=GG (CC, DD, AA, BB, x[11], S23, 0x265e5a51) # 19

   BB=GG (BB, CC, DD, AA, x[ 0], S24, 0xe9b6c7aa) # 20

   AA=GG (AA, BB, CC, DD, x[ 5], S21, 0xd62f105d) # 21

   DD=GG (DD, AA, BB, CC, x[10], S22,  0x2441453) # 22

   CC=GG (CC, DD, AA, BB, x[15], S23, 0xd8a1e681) # 23

   BB=GG (BB, CC, DD, AA, x[ 4], S24, 0xe7d3fbc8) # 24

   AA=GG (AA, BB, CC, DD, x[ 9], S21, 0x21e1cde6) # 25

   DD=GG (DD, AA, BB, CC, x[14], S22, 0xc33707d6) # 26

   CC=GG (CC, DD, AA, BB, x[ 3], S23, 0xf4d50d87) # 27

   BB=GG (BB, CC, DD, AA, x[ 8], S24, 0x455a14ed) # 28

   AA=GG (AA, BB, CC, DD, x[13], S21, 0xa9e3e905) # 29

   DD=GG (DD, AA, BB, CC, x[ 2], S22, 0xfcefa3f8) # 30

   CC=GG (CC, DD, AA, BB, x[ 7], S23, 0x676f02d9) # 31

   BB=GG (BB, CC, DD, AA, x[12], S24, 0x8d2a4c8a) # 32



   # Round 3

   AA=HH (AA, BB, CC, DD, x[ 5], S31, 0xfffa3942) # 33

   DD=HH (DD, AA, BB, CC, x[ 8], S32, 0x8771f681) # 34

   CC=HH (CC, DD, AA, BB, x[11], S33, 0x6d9d6122) # 35

   BB=HH (BB, CC, DD, AA, x[14], S34, 0xfde5380c) # 36

   AA=HH (AA, BB, CC, DD, x[ 1], S31, 0xa4beea44) # 37

   DD=HH (DD, AA, BB, CC, x[ 4], S32, 0x4bdecfa9) # 38

   CC=HH (CC, DD, AA, BB, x[ 7], S33, 0xf6bb4b60) # 39

   BB=HH (BB, CC, DD, AA, x[10], S34, 0xbebfbc70) # 40

   AA=HH (AA, BB, CC, DD, x[13], S31, 0x289b7ec6) # 41

   DD=HH (DD, AA, BB, CC, x[ 0], S32, 0xeaa127fa) # 42

   CC=HH (CC, DD, AA, BB, x[ 3], S33, 0xd4ef3085) # 43

   BB=HH (BB, CC, DD, AA, x[ 6], S34,  0x4881d05) # 44

   AA=HH (AA, BB, CC, DD, x[ 9], S31, 0xd9d4d039) # 45

   DD=HH (DD, AA, BB, CC, x[12], S32, 0xe6db99e5) # 46

   CC=HH (CC, DD, AA, BB, x[15], S33, 0x1fa27cf8) # 47

   BB=HH (BB, CC, DD, AA, x[ 2], S34, 0xc4ac5665) # 48



   # Round 4

   AA=II (AA, BB, CC, DD, x[ 0], S41, 0xf4292244) # 49

   DD=II (DD, AA, BB, CC, x[ 7], S42, 0x432aff97) # 50

   CC=II (CC, DD, AA, BB, x[14], S43, 0xab9423a7) # 51

   BB=II (BB, CC, DD, AA, x[ 5], S44, 0xfc93a039) # 52

   AA=II (AA, BB, CC, DD, x[12], S41, 0x655b59c3) # 53

   DD=II (DD, AA, BB, CC, x[ 3], S42, 0x8f0ccc92) # 54

   CC=II (CC, DD, AA, BB, x[10], S43, 0xffeff47d) # 55

   BB=II (BB, CC, DD, AA, x[ 1], S44, 0x85845dd1) # 56

   AA=II (AA, BB, CC, DD, x[ 8], S41, 0x6fa87e4f) # 57

   DD=II (DD, AA, BB, CC, x[15], S42, 0xfe2ce6e0) # 58

   CC=II (CC, DD, AA, BB, x[ 6], S43, 0xa3014314) # 59

   BB=II (BB, CC, DD, AA, x[13], S44, 0x4e0811a1) # 60

   AA=II (AA, BB, CC, DD, x[ 4], S41, 0xf7537e82) # 61

   DD=II (DD, AA, BB, CC, x[11], S42, 0xbd3af235) # 62

   CC=II (CC, DD, AA, BB, x[ 2], S43, 0x2ad7d2bb) # 63

   BB=II (BB, CC, DD, AA, x[ 9], S44, 0xeb86d391) # 64

Y por ultimo, se devuelven los valores que se tomaron de los buffer a ellos:
self.a=(self.a+AA)&0xFFFFFFFF

   self.b=(self.b+BB)&amp;0xFFFFFFFF

   self.c=(self.c+CC)&amp;0xFFFFFFFF

   self.d=(self.d+DD)&amp;0xFFFFFFFF

Una cosa... el hacer and con 0xFFFFFFFF a las variables es para evitar que ocupen mas de 32 bytes, otra forma seria hacerlo modulo 0x100000000, pero esta es mas rapida. Bien, veamos en que consisten las transformaciones... para empezar, S11,S12,S.. son constantes predefinidas, sus valores son estos:

Tabla de valores utilizados en la funcion

S11=7

S12=12

S13=17

S14=22

S21=5

S22=9

S23=14

S24=20

S31=4

S32=11

S33=16

S34=23

S41=6

S42=10

S43=15

S44=21

Funciones basicas

def F(x,y,z):

return (x&y)|((~x&0xFFFFFFFF)&z)

def G(x,y,z):

return (x&z)|(y&(~z&0xFFFFFFFF))

def H(x,y,z):

return x^y^z

def I(x,y,z):

return y^(x|(~z&0xFFFFFFFF))

Rotacion

def rotate_left(x,y):

return ((x<>(32-y)))

Transformaciones

def FF(a,b,c,d,x,s,ac):

a=(a+(F(b,c,d)+x+ac))&0xFFFFFFFF

a= rotate_left(a,s)&0xFFFFFFFF

a=(a+b)&0xFFFFFFFF

return a

def GG(a,b,c,d,x,s,ac):

a=(a+(G(b,c,d)+x+ac))&0xFFFFFFFF

a= rotate_left(a,s)&0xFFFFFFFF

a=(a+b)&0xFFFFFFFF

return a

def HH(a,b,c,d,x,s,ac):

a=(a+(H(b,c,d)+x+ac))&0xFFFFFFFF

a= rotate_left(a,s)&0xFFFFFFFF

a=(a+b)&0xFFFFFFFF

return a

def II(a,b,c,d,x,s,ac):

a=(a+(I(b,c,d)+x+ac))&0xFFFFFFFF

a= rotate_left(a,s)&0xFFFFFFFF

a=(a+b)&0xFFFFFFFF

return a

Y por ultimo, se presenta como resultado lo que hay en los buffers, comenzando por el byte menos significativo de A y acabando por el mas significativo de D, normalmente se hace directamente en la representacion hexadecimal:
def final(self):

   self.digest=[]

   for some in [self.a,self.b,self.c,self.d]:

       t=uint4tochar(some)

       while len(t)>0:

           thing=t.pop(len(t)-1)

           self.digest.append(myhex(thing)[2:4])

def hexdigest(self):

   from string import join

   return join(self.digest,'')

Las funciones utilizadas son estas:

Pasa un entero de 4 bytes a un array de 4 bytes

def uint4tochar(s):

i=0

t=[0,0,0,0]

while i<4:

   aux=(s>>(8*i))&0xFF

   t[3-i]=int(aux)

   i+=1

return t

Devuelve un hexadecimal con 4 caracteres o mas

def myhex(a):

r=hex(a)

if (len(r)==3):

   r="0x0"+r[2]

return r

El código completo aqui [md5.py]

Si se ejecuta directamente (no importandolo), hace unas pruebas para comprobar que funciona bien, las comprobaciones se hacen contra hashlib:

===============================================================================

d41d8cd98f00b204e9800998ecf8427e = d41d8cd98f00b204e9800998ecf8427e True 81dc9bdb52d04dc20036dbd8313ed055 = 81dc9bdb52d04dc20036dbd8313ed055 True 9e107d9d372bb6826bd81d3542a419d6 = 9e107d9d372bb6826bd81d3542a419d6 True e4d909c290d0fb1ca068ffaddf22cbd0 = e4d909c290d0fb1ca068ffaddf22cbd0 True 6f728eb0a9ef9387cb17dba7cc2116fb = 6f728eb0a9ef9387cb17dba7cc2116fb True

===============================================================================

Hasta la proxima ;)

[Referencia] RFC_1321 MD5_-_Wikipedia Otra_implementacion

class md5:

def init(self,s):

ln=len(s)*8

self.padd(s)

self.attach_len(ln)

self.buff_init()

self.update(ln)

self.final()

===============================================================================

Web's fantasma

Era un concepto que me gusto, la verdad es que ni siquiera era idea mia, sino que la saque de #_Freesoftwareando_in_the_night, la idea era dejar ahí el zip... pero como cerraron el post, pues lo dejo aqui.

Lo que entendi grosso modo (seguramente estaria explicado exactamente lo contrario, pero se hace lo que se puede  ), era que estaria bien tener paginas web que una vez se visitaran, al volver no hubiera nada, por aquello de que alguien viendo de donde venia la gente por los Refereer acabaria estrellandose con un 404, bien, lo que pude programar es esto [multiplexor.zip], (hay que ajustar algunos parametros en options.php)

Y basicamente lo que hace es que al navegar dentro de la pagina (para empezar hay que navegar al archivo getticket.php) todas las direcciones son "virtuales", si alguien las ve y intenta visistarlas se encontrara con el conocido 404 Not Found, en la practica lo que hace es cifrar con ARC4 el nombre del archivo de la url usando como contraseña el id de session, y que al descifrar si no encuentra nada, envie un 404.

Obviamente no todo son ventajas (acaso tiene alguna utilidad real? ), el script PHP hace una peticion al servidor por cada una que le hace a el (siendo a localhost no deberia haber gran problema, pero es algo a tener en cuenta), ademas el problema de la implementacion es que seguramente funcione mal en paginas con Ajax, y no se tomo en cuenta la posibilidad de usarlo con formularios (es una Prueba de concepto, no habia ganas de implementar un parser html completo y demas )

ps: Perdon desde ya por el ultimo trozo de codigo, me quedo bastante... poco pythonico

ps2: Para quien no quiera bajarse todo el zip, tiene la implementacion de ARC4 en php, en unzip_separado

Eso es todo, hasta la proxima!