Una función hash criptográfica es una clase especial de función hash que tiene ciertas propiedades que la hacen adecuada para su uso en criptografía. Es un algoritmo matemático que asigna datos de tamaño arbitrario a una string de bits de un tamaño fijo (una función hash) que está diseñado para ser también una función unidireccional, es decir, una función que no es factible de invertir. En este artículo, comprendamos uno de esos tipos de hash con tamaño de hash variable.
Los esquemas tradicionales de RSA Signature se basan en la siguiente secuencia de pasos:
- Obtener el mensaje a firmar digitalmente – M
- Use SHA o algún otro algoritmo hash para generar el resumen del mensaje: H = Hash (M)
- Cifre el resumen del mensaje con la clave privada del firmante. Los resultados del cifrado son la firma del mensaje: S = E (PrivateKey, H)
Un déficit potencial en el esquema ilustrado anteriormente es que el sistema RSA termina siendo infrautilizado . Supongamos que el módulo RSA es del orden de 2048 bits. Esto significa que la entrada puede ser cualquier valor con hasta 2048 bits. Sin embargo, en el esquema de firma, la entrada al sistema RSA es consistentemente del mismo tamaño, el tamaño del hash-digest. Por lo tanto, si, por ejemplo, se utiliza SHA-512 en el esquema de firma, todas las entradas a la función RSA serán consistentemente de 512 bits. Esto deja la mayoría ( > 99 % en este caso) del espacio de entrada de RSA sin utilizar. Esto tiene el efecto de reducir el nivel de seguridad general del sistema RSA como resultado de la infrautilización del espacio de entrada.
El esquema Full Domain Hashing (FDH) en los esquemas RSA Signature mitiga esta infrautilización al convertir el mensaje en el dominio completo del criptosistema RSA. El objetivo de FDH, por lo tanto, es:
Hash un mensaje usando una función cuyo tamaño de imagen/tamaño de resumen es igual al tamaño del módulo RSA
Los dos enfoques básicos para realizar una función que puede producir un resumen de tamaño arbitrario son:
- Hashing repetidamente el mensaje (con ligeras modificaciones) y concatenación
- Uso de métodos hash de función de salida extensible (XOF)
Hashing repetido con concatenación
Aunque los algoritmos hash tradicionales como SHA1, SHA256, SHA512 no tienen el rango suficiente para cubrir los dominios de entrada de los sistemas RSA, podemos construir un método hash de dominio completo mediante la aplicación repetida de estas funciones hash. La función hash estándar, digamos SHA512, se aplica al mensaje repetidamente, concatenando los resultados cada vez. Esto se hace hasta que se alcanza el número requerido de bits.
Para introducir el comportamiento aleatorio de las funciones hash, en lugar de aplicar hash al mismo mensaje repetidamente, se introducen algunas modificaciones al mensaje en cada iteración antes de realizar el hash. Un ejemplo de una modificación de este tipo sería concatenar el recuento de iteraciones al mensaje, antes del hash. Así, una función FDH se realiza como:
Si el hash SHA512 se calculó y concatenó N veces, el hash general tendrá un tamaño de bit de N * 512 . Suponiendo que este valor es mayor que el número requerido, ‘K’ , de bits, podemos extraer los K bits principales para obtener el hash de longitud deseado.
A continuación se muestra la implementación del enfoque anterior:
Python3
# Python program to demonstrate # repeated hashing with # concatenation import binascii from math import ceil from hashlib import sha256 # Function to perform Full Domain # Hash of 'message' using # SHA512 with a digest of # N bits def fdh(message, n): result = [] # Produce enough SHA512 digests # to make a composite digest # greater than or equal to N bits for i in range(ceil(n / 256)): # Append iteration count # to the message currentMsg = str(message) + str(i) # Add current hash to results list result.append(sha256((currentMsg).encode()).hexdigest()) # Append all the computed hashes result = ''.join(result) # Obtaining binary representating resAsBinary = ''.join(format(ord(x), 'b') for x in result) # Trimming the hash to the # required size by taking # only the leading bits resAsBinary = resAsBinary[:n] # Converting back to the # ASCII from binary format return binascii.unhexlify('00%x' % int(resAsBinary, 2)).hex() # Driver code if __name__ == '__main__': # Message to be hashed message = "GeeksForGeeks" # Generate a 600 bit # hash using SHA256 print(fdh(message, 600))
00cf161c36df4db9e30d79cf9cb3d72e1934cbaeb9eb8638f0d71f1872679e1df9c3932c77c70c98efa64d34e3166c5b698738b36d9b36b87261c5ae3c61871bc3608ed19
Uso de métodos hash de función de salida extensible (XOF)
Las funciones de salida extensible son una clase de funciones hash que, a diferencia de las funciones hash tradicionales, pueden generar una secuencia arbitrariamente grande de bits en el resumen de un mensaje. Esto contrasta fuertemente con las funciones hash regulares que se definen por un tamaño de salida fijo. En el esquema SHA-3 recientemente introducido, XOF se proporciona utilizando los algoritmos SHAKE128 y SHAKE256 . Se derivan de las propiedades generales de la construcción de la esponja . Una función de esponja puede generar una longitud arbitraria de la salida. Los 128 y 256 de sus nombres indican su máximo nivel de seguridad (en bits), tal como se describe en las Secciones A.1 y A.2 de FIPS 202 .
Para aprovechar la funcionalidad de SHA-3 en Python, la biblioteca PyCryptodome se puede utilizar de la siguiente manera:
Python3
# Python program to demonstrate # the SHA-3 algorithm from Crypto.Hash import SHAKE256 from binascii import hexlify # Instantiate the SHAKE256 object shake = SHAKE256.new() # Set the message to be hashed shake.update(b'GeeksForGeeks') # Print a hash output of 50 bits size print(hexlify(shake.read(50)))
Producción:
b’65d6df8d88198de69b3cf59b859d72971b93f102ca20af812b931714a558c7a134cb3bb085835f470c890bd1d50928355358′
Nota: El código anterior no se ejecutará en los IDE en línea porque los IDE en línea carecen de la biblioteca Crypto.