The homework for this week, was "Implement RSA authentication in Python for a client-server system with sockets"
So, this is my work:
RSA, is an algorithm for cryptography and consist in generate two keys (public and private key) one pair for participant, for encrypt one message.
Basically the steps for create the keys are:
- Choose two prime numbers, p and q.
- Calculate n = p*q
- Calculate φ(n) = (p-1) * (q-1)
- Choose e, such that : 1<e<φ(n) and e, φ(n) are coprimes
- Calculate : Inverse mod of e mod φ(n)
- The public key are (n, e)
- The private key are (n, d)
then convert the plain number to the message.
For convert the message to a number and a number to a message, i used the ascii code from every character in the message.
For choose the value of e and calculate d, i used the extended euclidean algortihm, i wrote something about this in Extended Euclidean Algorithm, (originally thist post was for cripto, but i had an error choosing the correct blog ) and the library gmpy2, for calculate the modular inverse for obtain the value of d.
Here is are my codes:
script for the server:
import socket
import random
import gmpy2
def enviar(algo, server_c):
#algo = str(algo)
server_c.send(str(algo)) #enviar algo al cliente conectado
return
def recibir(server_c):
algo = server_c.recv(2048) #recibir algo del cliente (maximo en bytes a recibir)
#algo = int(algo)
return algo
def encriptar(np, e_r, n_r):
ne_e = (pow(np, e_r)) % n_r
return ne_e
def desencriptar(ne_r, d, n):
ne_r = int(ne_r)
np_r = (pow(ne_r, d)) % n
return np_r
def crear_primo(longitud):
#longitud en bits, es necesario que sea parecida entre p y q
primo = random.randint(2**(longitud-1),2**longitud)
primo |= 1 #lo hacemos impar
return primo
def extended_gcd(a, b):
x, ant_x = 0, 1
y, ant_y = 1, 0
while b:
cociente = a // b
a, b = b, a % b
x, ant_x = ant_x - cociente*x, x
y, ant_y = ant_y - cociente*y, y
return (ant_x, ant_y, a)
def f(x):
y = x*31
def main():
server = socket.socket() #iniciar el servidor
server.bind(("localhost", 9999)) #establecer (nombre host, puerto)
server.listen(1) #numero de conexiones entrantes
print "Esperando conexion una entrante... "
server_c, direccion = server.accept() #aceptar conexion con un cliente
print "Conectado!... "
p = crear_primo(8)
#p = 283
q = crear_primo(8)
#q = 163
n = p*q
phi = (p - 1)*(q - 1)
gcd = 0
while (gcd != 1): #buscar el exponente publico e
e = crear_primo(random.randint(8, 15))
x, c, gcd = extended_gcd(e, phi)
d = gmpy2.invert(e, phi)
#se forma clave publica (n, e)
#se forma la clave privada (n, d)
enviar(n, server_c)#se envia la clave publica
enviar(e, server_c)
print "Clave publica enviada... "
print n, e
usuarios = ["alex", "david", "ale"]
x = random.randint(0, 50)
X = f(x)
enviar(x, server_c)
print "x enviado : "
usuario = recibir(server_c)
x_r = recibir(server_c)
x_r = int(x_r)
if (usuario in usuarios):
print " User : ", usuario, " correcto... "
y = desencriptar(x_r, d, n)
if (X==y):
print "Bienvenido!!......"
else:
"Numero incorrecto..."
else:
print " User incorrecto..."
server.close()
server_c.close()
main()
script for the client:
import socket
def enviar(algo, client):
#algo = str(algo)
client.send(str(algo)) #enviar algo al cliente conectado
return
def recibir(client):
algo = client.recv(2048) #recibir algo del cliente (maximo en bytes a recibir)
#algo = int(algo)
return algo
def encriptar(np, e_r, n_r):
ne_e = (pow(np, e_r)) % n_r
return ne_e
def desencriptar(ne_r, d, n):
ne_r = int(ne_r)
np_r = (pow(ne_r, d)) % n
return np_r
def f(x):
y = x*31
def main():
client = socket.socket() #iniciar el cliente
client.connect(("localhost", 9999)) #establecer conexion a (nombre host, puerto)
print "Conectado!... "
n_r = recibir(client) #se recibe la clave publica
e_r = recibir(client)
print "Clave publica recibida... "
n_r = int(n_r)
e_r = int(e_r)
print n_r, e_r
x_r = recibir(client) #se recibe el numero x
x_r = int(x_r)
X = f(x_r)
user = raw_input("Ingrese su usuario: ")
y = encriptar(int(X), e_r, n_r)
enviar(user, client) #se envian los datos
enviar(y, client)
usuario = recibir(server_c)
x_r = recibir(server_c)
x_r = int(x_r)
client.close()
main()
Here the captures of this running:
Then, just for fun, i try to write a code for emulate a simple chat or somethin like that.
The code for the server version:
import socket
import random
import gmpy2
def enviar(algo, server_c):
#algo = str(algo)
server_c.send(str(algo)) #enviar algo al cliente conectado
return
def recibir(server_c):
algo = server_c.recv(2048) #recibir algo del cliente(max en bytes)
#algo = int(algo)
return int(algo)
def msg_num(mensaje_e):
np_e = 0
for char in mensaje_e:
np_e <<= 8
np_e += ord(char)
#print np_e
return np_e
def num_msg(np_r):
nm = []
while np_r > 0:
#nm >>= 8
nm.insert(0, chr(np_r & 255))
np_r >>= 8
mensaje_r = "".join(nm)
#print mo
return mensaje_r
def encriptar(np, e_r, n_r):
ne_e = (np ** e_r) % n_r
return ne_e
def desencriptar(ne_r, d, n):
ne_r = int(ne_r)
np_r = (ne_r ** d) % n
return np_r
def crear_primo(longitud):
#longitud en bits, es necesario que sea parecida entre p y q
primo = random.randint(2**(longitud-1),2**longitud)
primo |= 1 #lo hacemos impar
return primo
def extended_gcd(a, b):
x, ant_x = 0, 1
y, ant_y = 1, 0
while b:
cociente = a // b
a, b = b, a % b
x, ant_x = ant_x - cociente*x, x
y, ant_y = ant_y - cociente*y, y
return (ant_x, ant_y, a)
def main():
server = socket.socket() #iniciar el servidor
server.bind(("localhost", 9999)) #establecer (nombre host, puerto)
server.listen(1) #numero de conexiones entrantes
print "Esperando conexion una entrante... "
server_c, direccion = server.accept() #aceptar conexion con un cliente
print "Conectado!... "
p = crear_primo(8)
q = crear_primo(8)
n = p*q
phi = (p - 1)*(q - 1)
gcd = 0
while (gcd != 1): #buscar el exponente publico e
#(menor que phi y que sea coprimo de phi)
e = crear_primo(random.randint(8, 15))
x, c, gcd = extended_gcd(e, phi)
d = gmpy2.invert(e, phi) #calcular el exponente privado d
#se forma clave publica (n, e)
#se forma la clave privada (n, d)
enviar(n, server_c)#se envia la clave publica
enviar(e, server_c)
print "Clave publica enviada... "
print n, e
n_r = recibir(server_c) #se recibe la clave publica
e_r = recibir(server_c)
print "Clave publica recibida... "
print n_r, e_r
mensaje_r = "-"
print "Iniciando el envio de mensajes... "
while (mensaje_r != "fin") : #mantener la conexion y el envio de mensajes
#enviar mensajes
mensaje_e = raw_input("Ingrese el mensaje a enviar: ")
np_e = msg_num(mensaje_e)
print "numero plano a enviar : ", np_e
ne_e = encriptar(np_e, e_r, n_r)
enviar(ne_e, server_c)
print "numero encriptado a enviar : ", ne_e
print "Mensaje enviado... "
#recibir mensajes
ne_r = recibir(server_c)
print "numero encriptado recibido : ", ne_r
np_r = desencriptar(ne_r, d, n)
print "numero plano recibido : ", np_r
mensaje_r = num_msg(np_r)
print "Mensaje recibido: ", mensaje_r
server.close()
server_c.close()
main()
The code for the client version, practically are the same that the server version, just change in the part of the sockets, the functions for recive, send, encrypt, decrypt are the same.
client = socket.socket() #iniciar el cliente
client.connect(("localhost", 9999)) #establecer conexion
print "Conectado!... "
Here an capture from the codes running:
Unfortunately, the programs don´t run at 100%, i have troubles with the decryption of the number and for consequence the message don´t shows like the original message, i´m not sure what i´m doing wrong :/.
________________________________________________________________________________
References:
http://en.wikipedia.org/wiki/RSA_%28algorithm%29
http://en.wikipedia.org/wiki/Coprime
http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
http://temasinteligencia.blogspot.mx/2012/08/algoritmo-de-euclides-extra.html







