Hola a todos, hace poco he creado un algoritmo generador de hashes, la verdad es que en dos días ya le he encontrado un montón de fallos, y se lo she arreglado, por supuesto.
No he hecho ningún estudio teórico sobre él, y no se si es demasiado seguo, no se si se producen colisiones fácilmente, no se si se pueden deducir contenidos que generen el hash a partir del él...
Así que dejaré mi algoritmo escrito, para someterlo a revisión, explicaré cada parte, a ver que os parece :P .
El hash constaría de 128 bits(aunque su estructura es tan sencilla que se podria ampliar cómodamente a millones de bits, si me lo propusiera, claro, :P). tengo pensado ampliarlo a 160 bits, pero no se en que medida esto aumentaría la seguridad, por eso presento aquí el algoritmo.
Pues bien, los primeros 4 bytes se inicializan con un valor entero de 32 bits, yo puse "0xABCDEF01"(es en hexadecimal), no se que impacto puede tener el que sea de un modo u otro, ese número inicial.
Los otros 4 bytes siguientes se inicializan con un entero que representa la longitud del mensaje a digerir, pero en modulo 2^32. Así podría digerir más de medio giga, aunque lo representaría como sivolviera a empezar desde 0.
los 8 bytes restantes se inicializan con 0.
bueno, a partir de entonces, se van llenando los espacios que quedan con los bytes del mensaje. cuando se llega al final de la matriz(la del hash), se empieza a llenar una segunda matriz vacía de la misma longitud que la del hash. Si se acabara el mensaje, se seguría llenando hasta llenar porlomenos la segunda matriz. pero se llenaría otra vez con la secuencia numerica inicial, y después la longitud del mensaje. Si el mensaje fuera más largo que la longitud de las dos matrices, los siguientes bytes se sumarian a los ya existentes de la primera matriz, como en un bucle, así llenaría otra vez la primera matriz, i si fuera necesaria continuaría también con la segunda..
Bien, una vez sumado todo, cuando ya se han llenado las amtrices con esos valores, se suman las dos matrices, y se almacena el resultado en la primera, de la forma A[i] = A[i] + B[i].
Asta aquí es nmuy sencillo, aquí no se acaba, pues en este punto, se podrian obtener millones de colisiones muy fácilmente, se pueden obtener muchas cadenas que satisfagan el resultado de esas sumas.
Lo siguiente es la difusion, esto se hace para que si un mensaje tiene pocas diferencias respecto al anterior, esas diferencias afecten a todo el hash i no solamente unos bloques. La difusion que yo hago es la siguiente, no la hago habiendo finalizado las sumas, la hago durante las sumas(antes de sumar las dos matrices).
cojo el elemento de la matriz que acabo de sumar, y xoreo los dos elementos adyacentes con este, al ir prosiguiendo con las sumas, el xoreo que se ha hecho con el único elemento cambiado ha acabado afectando a todo el hash.
Esto, como he dicho es para la difusión, y aunque también dificulta un poco el plantear los sistemas de ecuaciones que permitan resolver las cadenas que cumplen con le hash hasta ahora hecho, una vez planteados esos ssitemas ya no hay mayor dificultad.
Bien, ahora viene lo que dificulta, creo yo, lo de las colisiones.
cojo el primer entero de 4 bytes del hash, y con el resultado del entero_modulo_longitudmensaje selecciono un byte del mensaje, este byte lo multiplico por ese entero, y el resultado lo aplicamos al entero también.
con el segundo, el tercer, y el cuarto entero se hace lo mismo. con esto se hace que el número que se muestra en el hash no solo depende de las sumas y la difusión, sinó de otros carácteres del mensaje.
Ah, me olvidaba, esa multiplicación, no se hace realmente entre el entero y el byte del mensaje, se hace así: entero*(byte_mensaje+entero_siguiente).
Esto del entero siguiente es por si el byte del mensaje fuese 0, entonces la homogeneidad del hash quedaria anulada, y además, se podrian deducir más fácilmente mensajes que produjeran ese hash, creo.
Lo que he visto ahora , mientras escribía..., cuando hago la difusión, al hacerla mientras se procesan las sumas, si que interviene mucho el cómo sea el mensaje, y no sólo el resultado de las sumas, porque como todavía no hay resultados fijos eso va variando. Sería entonces realmente útil la capa de las multiplicaciones, o se podria considerar una parafernalia para hacer creer que es mas seguro y ya esta?
el problema está en que al escribir código puse lo de la difusion después de cada suma, y no despues del resultado, ahora me parece más seguro, pero no lo pensé con ese proposito al escribir el código.. :P
Aquí teneis el código en c, da el resumen hash de cualquier archivo que le indiqueis, es como un md5sum pero sin tener la confirmación de ser seguro.
// HASHER.CPP #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "CSCHasher_private.h" union quadbyte { unsigned int i; unsigned char c[4]; }; union cschash { unsigned int i[8]; unsigned char c[32]; }; int main(int argc, char* argv[]) { FILE* arch; putchar('\n'); for(int x = 1; x < argc; x++) { if((arch = fopen(argv[x], "rb+"))==0) { printf("El archivo no es accesible.\n"); exit(1); } fseek(arch, 0, SEEK_END); int archsize = ftell(arch); fseek(arch, 0, SEEK_SET); cschash hashete; memset(&hashete, 0, sizeof(cschash)); hashete.i[0] = 0xABCDEF01; hashete.i[1] = archsize; unsigned int _size = archsize; for(register int i=8; (i<_size+8) || (i<32); i++) { hashete.c[i%32] += (unsigned char)(fgetc(arch)); if(i%32 < 31) hashete.c[(i%32)+1] ^= hashete.c[i%32]; else hashete.c[0] ^= hashete.c[31]; if(i%32 > 0) hashete.c[(i%32)-1] ^= hashete.c[i%32]; else hashete.c[31] ^= hashete.c[0]; if(i>=(_size+7) && i < 32) { quadbyte tmp; hashete.c[(++i)%32] += 0x01; hashete.c[(++i)%32] += 0xEF; hashete.c[(++i)%32] += 0xCD; hashete.c[(++i)%32] += 0xAB; tmp.i = archsize; hashete.c[(++i)%32] += tmp.c[0]; hashete.c[(++i)%32] += tmp.c[1]; hashete.c[(++i)%32] += tmp.c[2]; hashete.c[(++i)%32] += tmp.c[3]; _size *= 2; _size += 8; rewind(arch); } } for(register int i = 0; i < 16; i++) hashete.c[i] += hashete.c[i+16]; // Hago estas multiplicaciones 4 veces para crear un segundo // efecto de difusión, ya que puede ser necesario en mensajes // con un carácter repetido más de ocho veces consecutivas. // Al estar repetido tantas veces, pueden quedar fijados los // valores de hasta 3 bytes( o +), sin cambio alguno, de ahí el uso de // estas multiplicaciones. unsigned int i = hashete.i[0]; fseek(arch, (unsigned)(hashete.i[0]%(archsize)), SEEK_SET); hashete.i[0] *= ((fgetc(arch))+hashete.i[1]); fseek(arch, (unsigned)(hashete.i[1]%(archsize)), SEEK_SET); hashete.i[1] *= ((fgetc(arch))+hashete.i[2]); fseek(arch, (unsigned)(hashete.i[2]%(archsize)), SEEK_SET); hashete.i[2] *= ((fgetc(arch))+hashete.i[3]); fseek(arch, (unsigned)(hashete.i[3]%(archsize)), SEEK_SET); hashete.i[3] *= ((fgetc(arch))+i); i = hashete.i[3]; fseek(arch, (unsigned)(hashete.i[3]%(archsize)), SEEK_SET); hashete.i[3] *= ((fgetc(arch))+hashete.i[2]); fseek(arch, (unsigned)(hashete.i[2]%(archsize)), SEEK_SET); hashete.i[3] *= ((fgetc(arch))+hashete.i[1]); fseek(arch, (unsigned)(hashete.i[1]%(archsize)), SEEK_SET); hashete.i[2] *= ((fgetc(arch))+hashete.i[0]); fseek(arch, (unsigned)(hashete.i[0]%(archsize)), SEEK_SET); hashete.i[0] *= ((fgetc(arch))+i); i = hashete.i[0]; fseek(arch, (unsigned)(hashete.i[0]%(archsize)), SEEK_SET); hashete.i[0] *= ((fgetc(arch))+hashete.i[1]); fseek(arch, (unsigned)(hashete.i[1]%(archsize)), SEEK_SET); hashete.i[1] *= ((fgetc(arch))+hashete.i[2]); fseek(arch, (unsigned)(hashete.i[2]%(archsize)), SEEK_SET); hashete.i[2] *= ((fgetc(arch))+hashete.i[3]); fseek(arch, (unsigned)(hashete.i[3]%(archsize)), SEEK_SET); hashete.i[3] *= ((fgetc(arch))+i); i = hashete.i[3]; fseek(arch, (unsigned)(hashete.i[3]%(archsize)), SEEK_SET); hashete.i[3] *= ((fgetc(arch))+hashete.i[2]); fseek(arch, (unsigned)(hashete.i[2]%(archsize)), SEEK_SET); hashete.i[3] *= ((fgetc(arch))+hashete.i[1]); fseek(arch, (unsigned)(hashete.i[1]%(archsize)), SEEK_SET); hashete.i[2] *= ((fgetc(arch))+hashete.i[0]); fseek(arch, (unsigned)(hashete.i[0]%(archsize)), SEEK_SET); hashete.i[0] *= ((fgetc(arch))+i); fclose(arch); printf("%s -- %08x%08x%08x%08x\n", argv[x], hashete.i[0], hashete.i[1], hashete.i[2], hashete.i[3]); } if(argc == 1) { printf("%s version: %s\n\nEl programa necesita argumentos. Ejemplo:\n", PRODUCT_NAME, VER_STRING); printf(" %s file_1 [file_2] ... [file_n]\n\n", INTERNAL_NAME); } else printf("\nPicadillo generado en %lu milisegundos.\n", clock()); return 0; } // Fin archivo
He reeditado este post, esto se parece más a un programa usable ahora.
He solucionado algunos problemas del mecanismo de hashing... si alguien supiera revisarlo, yo ya lo he mejorado unas cuantas veces.
usabilidad
franci20 Agosto 2005 - 12:56pm
No me meto en debilidades porque estoy poco puesto, pero si en la usabilidad. Este algoritmo requiere releer bytes que ya han sido leidos, y por tanto no puedes usarlo en pipelines, a no ser que tengas un bufer tan grande como el fichero que se transmite. Los dos que yo he usado, SHA1 y MD5 tienen la capacidad de leer y descartar los bytes, además tampoco necesitas saber desde el principio que cantidad de datos tendrás (no me parece mal incluir el tamaño en el hash, pero podria ser al final).
Ah, una prueba que puedes hacer es generar un fichero y todas sus variantes posibles en las que sólo cambie un bit. Repite el proceso, si no pasa esta prueba mínima, hasta el bit de paridad seria mejor }:->
--
Tomad y ejecutad todos en él, porque éste es mi Quantum. (Peibol)
Un poquillo de atención, ee.. :P
CaStarCo19 Agosto 2005 - 7:24pm
... Sólo escribo un poco para ver si alguien hace caso de este post... Me gustaría leer alguna respuesta interesante... yo ya he estado buscando fallos al sistem ay no puedo... no se si recordáis que hay una ley que indica qu eun criptosistema acostumbra a ser seguro ante su creador... y yo soy ese, me cuesta bastante encontrar fallos...
-GPG-
email : castarco@gmail.com
id: A4C86159
server: keyserver.kjsl.com
-GPG-
Ayuda?
CaStarCo5 Agosto 2005 - 6:24pm
Bueno, como no se como borrar las repuestas...(en esta antes ponía aprte del código), utilizaré esta para pedir sialguien es capaz de encontrar fallos a mi mecanismo de hashing..., ha tenido mas de 200 lecturas y nadie se ha atrevido a contestar..? Yo mismo encontré fallos sin saber mucho, nadie más experto podria ayudar?