En un post anterior puse un script en python para implementar la firma digital y el cifrado con el esquema de firma digital y el esquema de cifrado ElGamal, respectivamente, y en éste incluyo otro script en python para implementar el descifrado y la verificación de la firma digital con esos mismos esquemas, es decir, para las operaciones que se realizan en la comunicación en el lado del receptor.
Antes de ver el script, creo que conviene recordar cómo se realizan dichas operaciones, para lo que recomiendo leer este post en el que expliqué este asunto referido al caso de RSA, pero que es lo mismo para el caso de aplicar los esquemas de firma digital y de cifrado ElGamal.
El script que pongo a continuación implementa las operaciones de descifrado de la clave de sesión mediante el esquema de cifrado ElGamal y el descifrado del texto en claro mediante el algoritmo AES de criptografía simétrica en modo de operación CBC, mientras que la verificación de la firma digital se realiza utilizando el esquema de firma ElGamal.
El par de claves ElGamal, publica y privada, para los dos usuarios participantes en la comunicación, emisor y receptor, son las mismas que las que generé mediante el script que puse en esta entrada y utilicé en el post citado al principio: clave pública emisor, clave privada emisor, clave pública receptor, clave privada receptor.
Para simular la recepción del mensaje cifrado utilizo un archivo que se ha creado tras la ejecución del script que puse en el post citado al principio, comunicación.txt, y que contiene, codificada en base64, la siguiente información: el par de valores correspondientes al cifrado de la clave de sesión AES, el criptograma y el par de valores correspondientes a la firma digital.
Asimismo, para que el script funcione se necesita importar el siguiente módulo en el programa principal, que se encargará de hacer de forma eficiente las operaciones de exponenciación modular.
#!/usr/bin/env python # -*- coding: utf-8 -*- # ALGORITMO DE EXPONENCIACIÓN MODULAR RÁPIDA: # # Algoritmo utilizado en operaciones de exponenciación modular # con números muy grandes con objeto de hacerlas de forma # más eficiente. # # http://mikelgarcialarragan.blogspot.com/ def exp_modular_rapida(b, e, m): c = 1 e = bin(e)[2:] for i in range(0, len(e)): c = pow(c, 2, m) if e[i]=="1": c = c*b%m return c
El script es el siguiente:
- Script python para el descifrado y verificación de la firma digital ElGamal:
#!/usr/bin/env python # -*- coding: utf-8 -*- # DESCIFRADO Y VERIFICACIÓN DE FIRMA ELGAMAL: # # Descifrar y verificar firma digital utilizando el criptosistema ElGamal. # # http://mikelgarcialarragan.blogspot.com/ import hashlib from Crypto.Cipher import AES import pyasn1.type.univ from pyasn1.codec.der import decoder from base64 import b64decode from exponenciacion_modular_rapida import exp_modular_rapida # CIFRADO AES (CRIPTOGRAFÍA SIMÉTRICA). def descifrar_aes(criptograma,clave): iv = criptograma[:AES.block_size] descifrar = AES.new(clave, AES.MODE_CBC, iv) texto_claro = descifrar.decrypt(criptograma[AES.block_size:]).decode() return texto_claro[:-ord(texto_claro[len(texto_claro) - 1:])] # OBTENER DATOS DE LA CLAVE PÚBLICA ELGAMAL def clave_publica_elgamal(fichero_pem): f_clave_publica_elgamal = open(fichero_pem, "r") clave_publica = f_clave_publica_elgamal.read() clave_publica = clave_publica.replace("-----BEGIN ELGAMAL PUBLIC KEY-----","") clave_publica = clave_publica.replace("-----END ELGAMAL PUBLIC KEY-----","") datos_clave_publica_elgamal = pyasn1.codec.der.decoder.decode(b64decode(clave_publica.encode('ascii'))) f_clave_publica_elgamal.close() return datos_clave_publica_elgamal # OBTENER DATOS DE LA CLAVE PRIVADA ELGAMAL def clave_privada_elgamal(fichero_pem): f_clave_privada_elgamal = open(fichero_pem, "r") clave_privada =f_clave_privada_elgamal.read() clave_privada = clave_privada.replace("-----BEGIN ELGAMAL PRIVATE KEY-----","") clave_privada = clave_privada.replace("-----END ELGAMAL PRIVATE KEY-----","") datos_clave_privada_elgamal = pyasn1.codec.der.decoder.decode(b64decode(clave_privada.encode('ascii'))) f_clave_privada_elgamal.close() return datos_clave_privada_elgamal def main(): # MENÚ: # Se presenta el menú para que se seleccione una opción. salir = False while not salir: print ("") print ("*** MENÚ *****************************************") print ("1. Descifrar y verificar firma digital.") print ("2. Salir.") print ("") opcion = input("Por favor, seleccione una opción: ") if opcion == "1": print ("") print ("--- DESCIFRAR Y VERIFICAR FIRMA DIGITAL:") # Descifrar y verificar firma digital: se reciben el par de valores correspondientes al # cifrado de la clave de sesión AES, el criptograma y el par de valores correspondientes # a la firma digital. f_comunicacion = open("comunicacion.txt") datos_comunicacion = f_comunicacion.readlines() print ("[+] Clave de sesión AES cifrada (base64): (", datos_comunicacion[0].rstrip(), ",", datos_comunicacion[1].rstrip(),")") print ("[+] Criptograma (base64):", datos_comunicacion[2].rstrip()) print ("[+] Firma digital (base64): (", datos_comunicacion[3], ",", datos_comunicacion[4].rstrip(),")") # Se lee la clave privada del receptor para descifrar la clave de sesión. datos_clave_privada = clave_privada_elgamal("private_receptor.pem") print ("[+] Clave privada del receptor:") print (" p:", datos_clave_privada[0][0]) print (" g:", datos_clave_privada[0][1]) print (" k:", datos_clave_privada[0][2]) print (" a:", datos_clave_privada[0][3]) # Se descifra la clave de sesión AES con la que se cifró el texto en claro con la clave # privada del receptor (criptografía asimétrica). clave_sesion = exp_modular_rapida(int(b64decode(datos_comunicacion[0])), datos_clave_privada[0][0]-1-datos_clave_privada[0][3],int(datos_clave_privada[0][0])) clave_sesion = (clave_sesion * int(b64decode(datos_comunicacion[1])))%datos_clave_privada[0][0] print ("[+] Clave de sesión AES descifrada (hexadecimal):", hex(clave_sesion)[2:]) # Se descifra el criptograma con la clave de sesión AES (criptografía simétrica). texto_claro = descifrar_aes(b64decode(datos_comunicacion[2]),bytes.fromhex(hex(clave_sesion)[2:])) print ("[+] Texto claro descifrado con la clave de sesión AES:", texto_claro) # Se calcula el hash SHA-256 (256 bits) del texto en claro descifrado. h_M = (hashlib.sha256(texto_claro.encode()).digest()) print ("[+] Hash calculado para el texto en claro descifrado (hexadecimal):", h_M.hex()) # Se lee la clave pública del emisor para verificar la firma digital. datos_clave_publica = clave_publica_elgamal("public_emisor.pem") print ("[+] Clave pública del emisor:") print (" p:", datos_clave_publica[0][0]) print (" g:", datos_clave_publica[0][1]) print (" k:", datos_clave_publica[0][2]) # Se realizan los cálculos utilizando la clave pública del emisor (criptografía asimétrica) # para verificar la firma recibida. g_elevado_h_M = exp_modular_rapida(datos_clave_publica[0][1], int(h_M.hex(),16), int(datos_clave_publica[0][0])) print ("[+] g ** h'(M) =", g_elevado_h_M) k_elevado_r = exp_modular_rapida(datos_clave_publica[0][2], int(b64decode(datos_comunicacion[3])), int(datos_clave_publica[0][0])) r_elevado_s = exp_modular_rapida(int(b64decode(datos_comunicacion[3])), int(b64decode(datos_comunicacion[4])), int(datos_clave_publica[0][0])) print ("[+] (k ** r) * (r ** s) =", (k_elevado_r * r_elevado_s)%datos_clave_publica[0][0]) if g_elevado_h_M == (k_elevado_r * r_elevado_s)%datos_clave_publica[0][0]: print ("[+] Se ha verificado la firma digital del contenido de la comunicación con el resultado de FIRMA DIGITAL VÁLIDA.") else: print ("[+] Se ha verificado la firma digital del contenido de la comunicación con el resultado de FIRMA DIGITAL NO VÁLIDA.") elif opcion == "2": print ("*** FIN ******************************************") salir = True else: print ("*** ERROR: Opción no válida.") if __name__ == '__main__': main()
Lo ejecuto:
Tras leerse del fichero que simula la comunicación, comunicacion.txt: el par de valores correspondientes al cifrado de la clave de sesión AES, el criptograma y el par de valores correspondientes a la firma digital, lo primero que hace el script es descifrar la clave de sesión AES con la clave privada del receptor (criptografía asimétrica) y descifrar el texto en claro cifrado con ella por el emisor (criptografía simétrica).
Lo siguiente que hace el script es calcular el hash SHA-256 del texto en claro descifrado.
Y, finalmente, el script lee la clave pública del emisor para validar mediante el esquema de firma digital ElGamal (criptografía asimétrica) la firma digital que se ha recibido.
Tal y como se puede observar en la figura anterior, en este caso el proceso de verificación de la firma digital termina con éxito y, por tanto, quedarían acreditadas tanto la autenticidad como la integridad del mensaje recibido.
Quizás también te interese:
Comentarios
Publicar un comentario