viernes, 18 de julio de 2008

Hash (parte 2)

Funciones Hash (Parte 2)



continuacion de

Hash (parte 1)

---------------------

Teníamos en el artículo Introduccion Hash (Parte 1) varios problemas diseñando algo que al menos se parezca un poco a una función hash. Uno de ellos es el excesivo tamaño que tomaba el hash, entonces una idea sería trocear la cadena de entrada en porciones de tamaño fijo, procesar dichas porciones de alguna manera y unir en una sola todas esas porciones procesadas.

Primer intento, vamos a diseñar una función hash de juguete con una salida de 32 bytes, 256 bits como los profesionales :-) Para ello tomamos inicialmente la cadena y la rellenamos con el carácter 'x' si es necesario para que tenga una longitud múltiplo de 32. A un contexto inicialmente formado sólo por ceros le añadimos (vía xor) bloque a bloque toda la cadena de entrada.

Seguimos el interfaz estándar para funciones hash de Python (bueno, casi). Veamos un primer problema:

Código:
  >>> import hash01
>>> z = hash01.new()
>>> z.update("Demasiado al este es oeste")
>>> z.hexdigest()
'44656d61736961646f20616c2065737465206573206f65737465787878787878'

¿Ven la sucesión 787878...? se produce por las 'x' que concatenamos a la cadena que tiene menos de 32 caracteres. Un segundo problema: cada vez que se añada (con update) información, el hash debería variar de forma impredecible, pero...

Código:
 >>> z.update("Demasiado al este es oeste")
>>> z.hexdigest()
'0000000000000000000000000000000000000000000000000000000000000000'

¡Desastre!, al añadir de nuevo la misma cadena, el xor de los caracteres consigo mismos produce ¡solamente ceros!. Aún un tercer problema, veamos dos cadenas distintas que producen el mismo hash.

Código:
  >>> z1 = hash01.new()
>>> z2 = hash01.new()
>>> z1.update('Las palabras son baratas')
>>> z1.hexdigest()
'4c61732070616c616272617320736f6e20626172617461737878787878787878'
>>> z2.update('Las palabras son baratasxxxxxx')
>>> z2.hexdigest()
'4c61732070616c616272617320736f6e20626172617461737878787878787878'

Al poner unas cuantas 'x' al final de la cadena no modificamos en absoluto el resultado, esto es lógico por la forma en que hemos rellenado la cadena pero no deja de ser un problema.

Pero mejor las solucionamos una a una en una tercera parte de esta serie.

He aqui el codigo de fuente del Hash01

Código:
#!/usr/bin/env python
# coding: iso-8859-1

def new(cadena=''):
xx = hash01(cadena)
return xx

class hash01:
def __init__(self, cadena=''):
# Tamaño en bytes del resumen
self.digest_size = 32
# Inicialmente el contexto es todo ceros
self.contexto = '\0'*self.digest_size
if cadena != '':
self.update(cadena)
return

def update(self, cadena):
# Rellenar si la longitud de la entrada no es múltiplo de LONHASH
resto = len(cadena) % self.digest_size
if resto != 0:
cadena += 'x'*(self.digest_size-resto)

# Se hace un xor de cada bloque de digest_size caracteres
# con el contenido anterior del contexto almacenando el
# resultado como nuevo contexto
while cadena != '':
c, cadena = cadena[:self.digest_size], cadena[self.digest_size:]
tmp = ''
for i in range(self.digest_size):
tmp += chr(ord(self.contexto[i]) ^ ord(c[i]))
self.contexto = tmp
return

def digest(self):
return self.contexto

def hexdigest(self):
hd = ''
for caracter in self.digest():
hd += '%02x' %ord(caracter)
return hd

if __name__ == '__main__':
import sys
z = new()
z.update(sys.argv[1])
print z.hexdigest()


Bueno doy gracias por la ayuda proporcionada con el lenguaje Phyton a Jaime Suarez Martinez, y asi mismo por su buena aprobacion del documento.

Por: rufiopunkrock

No hay comentarios: