Repositorio de claves publicas
Para esta penúltima tarea se pidió implementar a través de comunicación por sockets un repositorio de claves públicas, así como la transmisión de correos cifrados.Los requisitos además de los mencionados, es autenticar que tanto como cliente y servidor sean ellos mismos, el cliente pueda hacer consulta al servidor de clave pública de algún usuario inscrito en su archivo. Todo esto se hará utilizando RSA como autenticación (para no repetir como funciona por favor checa este post).
Funciones
Lado del cliente
En el lado del cliente se creó un objeto de la clase cliente. La clase cliente cuenta con los siguientes métodos: Genera n, φ(n), e y d:def __init__(self,p,q): self.p = p self.q = q def genN(self): print 'p = ', self.p print 'q = ', self.q print 'n = ', self.p * self.q return (self.p * self.q) def genphiN(self): print 'phiN = ',((self.p - 1) * (self.q - 1)) return ((self.p - 1) * (self.q - 1)) def genE(self,n,phiN): while True: e = random.SystemRandom().randint(2,n-1) print 'e = ', e if funciones.gcd(max(phiN,e),min(phiN,e)) == 1: return e def genD(self,phiN,e): r, x, y = funciones.gcdExt(phiN,e) if y < 1: y = y + phiN return y
El siguiente método llama a todos los métodos anteriores, este método es llamado si es que nunca se ha creado una clave y la guarda en un archivo llamado claves.txt (almacenado en el lado del cliente). Si ya se ha creado abre un archivo, y almacena en el programa los valores de e, d y n.
def generarClave(self): n = self.genN() phiN = self.genphiN() while True: e = self.genE(n,phiN) d = self.genD(phiN,e) if d != 1: print 'e = ',e print 'd = ',d print 'n = ',n break return n,phiN,e,d # solo llamo a este metodo si nunca antes habia # entrado al servidor, es decir que no tengo el archivo def guardarClave(self,e,d,n): f = open('clave.txt','w') f.write(str(e)) f.write('\n') f.write(str(d)) f.write('\n') f.write(str(n)) f.write('\n') f.close()Lo que mencione anteriormente sucede en el archivo cliente.py el cual llama a la función claveCliente().
# creando la clave del usuario def claveCliente(): try: f = open('clave.txt') e = int(f.readline()) d = int(f.readline()) n = int(f.readline()) f.close() except: p = funciones.genNumPriRan(1000,9999) q = funciones.genNumPriRan(1000,9999) cl = Cliente(p,q) n,phiN,e,d = cl.generarClave() cl.guardarClave(e,d,n) return e,d,n
Subscripción
Lado cliente. Cuando se ejecuta el script cliente.py. Se tiene que propocionar el usuario, solo si ha accedido con anterioridad al servidor. Si es la primera vez, entonces el cliente debe de proporcionar su usuario, después el servidor le solicitará un correo electrónico.# solo es una verificacion de cuando se ejecute el programa def ingresoUsuario(argv): if len(argv) < 2: print 'Si estas o no registrado escribe tu usuario' while True: usuario = raw_input('> ') if usuario != '' and usuario != 'q' and usuario != 'quit()' and usuario != 'exit': break else: usuario = argv[1] return usuario
# creando la clave del usuario def claveCliente(): try: f = open('clave.txt') e = int(f.readline()) d = int(f.readline()) n = int(f.readline()) f.close() except: p = funciones.genNumPriRan(1000,9999) q = funciones.genNumPriRan(1000,9999) cl = Cliente(p,q) n,phiN,e,d = cl.generarClave() cl.guardarClave(e,d,n) return e,d,n
Llamando las funciones anteriores.
usuario = ingresoUsuario(argv) # si no existe el archivo entonces lo crea si no solo lo lee e,d,n = claveCliente() cliente.send(usuario+'|'+str(e)+'|'+str(n)) aceptoUsuario = cliente.recv(1024) print aceptoUsuario if aceptoUsuario == "No existes en mi BD dame tu correo": correo = raw_input("Introduce tu correo\n> ") cliente.send(correo) print 'Haz sido anadido al repositorio vuelve a iniciar sesion' elif aceptoUsuario == "Lo siento pero el usuario que quieres registrar ya existe\no haz cambiado tu clave publica.": cliente.close()
Lado servidor. El servidor recibe el usuario, después abre su archivo de usuarios.txt y compara si las claves enviadas coinciden con el usuario enviado.
usuario = ingresoUsuario(argv) # lo que hace es verificar que el usuario que mande coincida con # la clave que tenemos en nuestro registro, si no existe # mandamos solicitar el email #http://stackoverflow.com/questions/16222956/reading-a-file-line-by-line-into-elements-of-an-array-in-python?l\q=1 def verificar(sc,usuario,eClte,nClte): f = open('usuarios.txt') for line in f: datos = line.split("|") if usuario == datos[0]: if eClte == int(datos[2]) and nClte == int(datos[3]): print 'si estas en la bd' print 'correo: ', datos[1] f.close() return "OK" else: f.close() return "En uso" return "No existe" # si existe comparamos su clave publica con la del repo, si no coinciden lo sacamos o le decimos que su clave ha cambiado def verificarClaveUsuario(sc,usuario,eClte,nClte): print 'verificando clave de usuario y si no existe lo agrego' verifica = verificar(sc,usuario,eClte,nClte) if verifica == "No existe": # no existe y hay que registrarlo sc.send("No existes en mi BD dame tu correo") correo = sc.recv(1024) cadena = usuario+"|"+correo+"|"+str(eClte)+"|"+str(nClte)+"\n" f = open('usuarios.txt','a') f.write(cadena) f.close() return False elif verifica == "OK": sc.send("OK") return True else: sc.send(str("Lo siento pero el usuario que quieres registrar ya existe\no haz cambiado tu clave publica.")) return False
Autenticación
Lado cliente
# servidor me reta (reta al cliente) xS = str(cliente.recv(512)) print 'xS = ', xS xSDecifrada = funciones.firmarCifrar(int(xS),d,n,eSrv,nSrv) print 'Decifrada xS = ', xSDecifrada fxS = funciones.f(xSDecifrada) print 'fxS = ', fxS respuesta = funciones.firmarCifrar(int(fxS),d,n,eSrv,nSrv) print 'fxSCifrada = ',respuesta cliente.send(str(respuesta)) # esperamos respuesta al reto del servidor print "que dices server ",cliente.recv(512) # retamos al servidor x = funciones.genNumPriRan(100,999) print 'Mi reto como cliente' print 'x = ',x fx = funciones.f(x) print 'fx = ',fx # firmo y cifro x xCrfd = funciones.firmarCifrar(x,d,n,eSrv,nSrv) print 'xCF = ', xCrfd cliente.send(str(xCrfd)) # esperamos por respuesta del server retoAceptado = int(cliente.recv(512)) print 'fxcifrada(envioServer) = ', retoAceptado retoAceptado = funciones.firmarCifrar(retoAceptado,d,n,eSrv,nSrv) print 'respuesta = ',retoAceptado if retoAceptado == fx: print 'ok, es el servidor'
reto = int(sc.recv(512)) print '\n\nacepto reto funcion\n\n' print 'reto = ',reto # servidor acepta reto decifrado y quitando la firma xClte = funciones.firmarCifrar(reto,d,n,eClte,nClte) print 'xClte = ',xClte # aplico funcion f(X) al reto fxClte = funciones.f(xClte) print 'fxClte = ',fxClte # cifro el reto fxFC = funciones.firmarCifrar(fxClte,d,n,eClte,nClte) print 'reto cifrado = ',fxFC # devuelvo el reto sc.send(str(fxFC)) # espero respuesta respuesta = sc.recv(512)Lado servidor
codigonada
#!/usr/bin/python import funciones from clscliente import Cliente from socket import socket from time import sleep from sys import argv def main(): usuario = '' if len(argv) < 2: print 'Escribe tu nombre de usuario, si no cuentas con un usuario, escribelo y te registraremos' while True: usuario = raw_input('> ') if usuario != '' and usuario != 'q' and usuario != 'quit()' and usuario != 'exit': break else: usuario = argv[1] # si no existe el archivo entonces lo crea si no solo lo lee try: f = open('clave.txt') e = int(f.readline()) d = int(f.readline()) n = int(f.readline()) except: p = funciones.genNumPriRan(100,999) q = funciones.genNumPriRan(100,999) cl = Cliente(p,q) n,phiN,e,d = cl.generarClave() cl.guardarClave(e,d,n) # primero que nada tengo que establecer comunicacion con el server para poder mandar reto cliente = socket() cliente.connect(('127.0.0.1',57712)) print cliente.recv(512) # mensaje de bienvenida # recibo e y n del servidor datos = cliente.recv(512) datos = datos.split("|") eSrv = int(datos[0]) nSrv = int(datos[1]) # print 'eSrv = ',eSrv # print 'nSrv = ',nSrv # envio mi publica y usuario cadena = usuario+'|'+str(e)+'|'+str(n) cliente.send(cadena) # reto al servidor x = funciones.genNumPriRan(10,99) fx = funciones.f(int(x)) # firmo y cifro x xfrmCrfd = funciones.firmarCifrar(x,d,n,eSrv,nSrv) print 'x = ',x print 'xCF = ', xfrmCrfd print 'fx = ',fx # envia reto cliente.send(str(xfrmCrfd)) retoAceptado = int(cliente.recv(1024)) print 'fxcifrada(envioServer) = ', retoAceptado retoAceptado = funciones.firmarCifrar(retoAceptado,d,n,eSrv,nSrv) print 'respuesta = ',retoAceptado if retoAceptado == fx: print 'ok' else: print ' no coincide' cliente.close() # xS = cliente.recv(512) # xS = int(xS) # print 'xS = ', xS # cliente.send(cadena) # mi publica # cliente.close() # # operacion contraria # quitaFrm = funciones.expModRap(frmCfrd,dSrv,nSrv) # encX = funciones.expModRap(quitaFrm,e,n) # print 'es la x = ',encX # fx = funciones.f(x) # # print fx main()
Petición de clave
Lado de cliente
# solicita una clave publica if msj == "-d": # -dime la clave publica cliente.send("-d") sleep(1) usuario = raw_input('De quien quieres saber la clave publica\n> ') print usuario cliente.send(usuario) datos = cliente.recv(1024).split("|") if datos[0] != "Usuario no existe": correoR,eR,nR = datos[0],datos[1],datos[2] print 'correo: ', correoR print ' e: ', eR print ' n: ', nR else: print 'Usuario no existe'Lado del servidor
# pregunta por un usuario y regresa su publica y correo def preguntar(usuario): f = open('usuarios.txt') for line in f: datos = line.split("|") print datos if usuario == datos[0]: f.close() return datos[1],datos[2],datos[3] # correo,e,n # si no regresa nada es que no existe entonces no se puede hacer nada f.close() return None,None,None
if datos == "-d" or datos == "-e": usuario = sc.recv(1024) print usuario correo,e,n = preguntar(usuario) print correo print e print n if correo != None: cadena = correo+"|"+str(e)+"|"+str(n) print cadena sc.send(str(cadena)) else: sc.send("Usuario no existe")
Facilidad de uso
Cuando el cliente se conecta al servidor, este le muestra texto de ayuda que le dice que debe hacer dependiendo de la situación que quiera generar.def bienvenida(sc): sc.send(str('-d proporciona la clave publica del usuario solicitado\n')) sc.send(str('-e cifrar un mensaje al usuario que elegiste\n')) sc.send(str('-m decifrar un mensaje cifrado\n')) sc.send(str('-q desconectarte del servidor\n')) sc.send(str('-h Ayuda. muestra el texto anterior\n')) sleep(1)
Y en el lado del cliente, cuando este haciendo peticiones, para mostrar la ayuda se hace una llamada a la función ayuda() del lado del cliente.
def ayuda(): print '-d proporciona la clave publica del usuario solicitado\n' print '-e cifrar un mensaje al usuario que elegiste\n' print '-m decifrar un mensaje cifrado\n' print '-q desconectarte del servidor\n' print '-h Ayuda. muestra el texto anterior\n'
Cifrado y descifrado
def cifrarMensaje(eRcpt,nRcpt): mensaje = raw_input('Mensaje: ') c ='' for i in xrange(len(msj)): if ord(msj[i]) < 100: aux = "0" + str(ord(msj[i])) c += str(expModRap(int(aux),eRcpt,nRcpt)).zfill(8) # el tamano de bloque es 8 porque las n tienen tamano de hasta 8 else: c += str(expModRap(int(ord(msj[i])),int(eRcpt),int(nRcpt))).zfill(8) f = open('mensajecifrado.txt','w') f.write(c) f.close() def decifrarMsj(dRcpt,nRcpt): f = open('mensajecifrado.txt','r') msjCfr = f.readline() f.close() j = 0 letra = "" msj = "" for i in xrange(len(c)): j = j + 1 letra = letra+ c[i] if j == 8: j = 0 msj += str(chr(expModRap(int(letra),int(dRcpt),int(nRcpt)))) letra = "" print "texto decifrado:\n",decifro f = open('mensaje.txt','w') f.write(msj) f.close()
if msj == "-e": # -envia el mensaje cifrado cliente.send("-e") sleep(1) sabes = raw_input('Conoces la clave publica y correo del remitente[S/N]\n> ') if sabes == 'S' or sabes == 's': # se llama al metodo para cifrar todo de lado de cliente eR = raw_input('e del remitente\n> ') nR = raw_input('n del remitente\n> ') cifrarMsj(eR,nR) else: usuario = raw_input('Nombre de usuario del remitente\n> ') print usuario cliente.send(usuario) datos = cliente.recv(1024).split("|") if datos[0] != "Usuario no existe": correoR,eR,nR = datos[0],datos[1],datos[2] cifrarMsj(eR,nR)
else: print "Usuario no existe"
Código
cliente.py
clscliente.py
funciones.py
servidor.py
Referencias.
González, R. (S/A). Python para todos. España. En este libro se consulto lo referente a comunicación entre sockets. Disponible en pdf en: https://launchpadlibrarian.net/18980633/Python%20para%20todos.pdf
Revise el blog de Víctor Ríos, ya que al momento de estar descifrando un texto no estaba obteniendo el resultado esperado, entonces compare mi código con el de él y basicamente el cifrado que el hace con su código, mi parte del código hacía lo mismo, pero al desencriptar estaba olvidando establecer un tamaño fijo por bloque de cada letra para poder descifrar, porque si no, no iba a funcionar. Además cuando yo cifraba el texto quería pasarlo a ASCII y me daba errores, obviamente porque cuando cifraba obtengo un número que sobrepasa los caracteres del ASCII.
+ subscription
ReplyDelete+ one-way auth.
+ two-way auth.
+ query
+ encryption
+ decryption
+ ease of use
Hay algo raro con tu incrustación de código, bloques vacíos de una sola línea en blanco.
7 de 10 pts