示例#1
0
    def crea_sesion_a(self, nombre):
        """
        Se escribe el archivo como nombreA_nombreB_values
        :param nombre: Usuario con quien se desea establecer la comunicación
        :return: devuelve el secreto calculado a partir de las llaves del usuario con el nombre
        especificado
        """
        dicti = self.solicita_llaves(nombre)
        if not dicti["ok"]:
            return "Error:\n" + dicti["detalles"]

        ikb = PublicKey(base64.b64decode(dicti["llave_identidad"]))
        mkb = PublicKey(base64.b64decode(dicti["pre_llave"]))
        # genera la llave efimera
        efk_priv = PrivateKey.generate()
        # calcula el secreto como: DH(IKA,MKB) || DH(EKA, IKB) || DH(EKA,MKB)
        b1 = Box(self.sk, mkb).shared_key()
        b2 = Box(efk_priv, ikb).shared_key()
        b3 = Box(efk_priv, mkb).shared_key()
        secreto = b1 + b2 + b3
        # Genera un diccionario para escribir en un archivo las llaves de Bob
        dicc = {
            'ikb': base64.b64encode(ikb.__bytes__()),
            'mkb': base64.b64encode(mkb.__bytes__()),
            'efk_pub': base64.b64encode(efk_priv.public_key.__bytes__()),
            'secreto': base64.b64encode(secreto),
            'kenv': "",
            'krecib': "",
            "establecida": False,
            "tipo": "A"
        }
        # escribe el archivo
        json.dump(dicc, open(self.nombre + "_" + nombre + "_values", "w"))
        self.secreto = secreto
        return secreto
示例#2
0
class Usuario:

    configuracion = Configuracion

    def __init__(self, nombre, configuracion):
        self.nombre = nombre
        # definimos la configuracion
        Usuario.configuracion = configuracion
        # genera la llave publica y privada
        self.sk = PrivateKey.generate()
        self.pk = self.sk.public_key
        # genera una llave para firmar
        self.sig = nacl.signing.SigningKey.generate()

        # LLAVE PARA PASAR EL RETO SI ERES "EL_CJ_100_real_no_fake_un_link"
        # nacl.signing.SigningKey(base64.b64decode("Afj+pfA5WbJeGCabSBa7kNFXzzZoeHtcuSVxs3nAxtc="))

        # genera una llave para verificar
        self.vk = self.sig.verify_key
        # genera llaves de medio uso
        self.medk_priv = PrivateKey.generate()
        self.medk_pub = self.medk_priv.public_key
        self.medk = self.sig.sign(self.medk_pub.__bytes__())

        # El secreto temporal
        self.secreto = "scrt"

        # El reto que mando el servidor para firmarlo
        self.reto = ""

        # El socket que se tendrá durante toda la conexión
        self.socket_connection = socket.socket()
        self.socket_connection.connect(
            (configuracion.direccion, configuracion.puerto))

        # Los keviar y krecibir TEMPORALES
        self.kenv = ""
        self.krecib = ""

    def saludo(self):
        """
        genera un mensaje tipo saludo al servidor
        :return: Diccionario con tipo = reto si existe el usuario
        """
        # genera el saludo
        saludo = {'tipo': "saludo", 'nombre': self.nombre}
        paquete = crea_paquete(saludo)
        # envía el mensaje
        self.socket_connection.send(paquete)
        # Recibe la respuesta del servidor
        self.socket_connection.recv(2)
        paquete_recibido = json.loads(self.socket_connection.recv(1024))
        if paquete_recibido["ok"]:
            # Existe el usuario, cargamos las llaves
            dicc = json.load(open("keys_" + self.nombre, "r"))

            self.sk = PrivateKey(base64.b64decode(dicc["sk"]))
            self.pk = PublicKey(base64.b64decode(dicc["pk"]))
            self.sig = nacl.signing.SigningKey(base64.b64decode(dicc["sig"]))
            self.vk = nacl.signing.VerifyKey(base64.b64decode(dicc["vk"]))
            self.medk_pub = PublicKey(base64.b64decode(dicc["medk_pub"]))
            self.medk_priv = PrivateKey(base64.b64decode(dicc["medk_priv"]))
            self.medk = base64.b64decode(dicc["medk"])
            # Se asigna el reto
            self.reto = paquete_recibido["reto"]
        else:
            print "Error. El usuario " + self.nombre + " no existe."
        return paquete_recibido

    def autenticar(self):
        """
        Funcion que a partir del reto obtenido en el saludo, lo firma con firma_reto y se autentica al server.
        :param self
        :return: respuesta del servidor
        """
        return self.firma_reto(self.reto)

    def firma_reto(self, reto):
        """
        firma el mensaje reto que envio el servidor en el saludo y lo manda
        :param reto: string que envía el servidor
        :return: respuesta del servidor
        """
        # genera el mensaje
        auth = {
            "tipo": "telofirmo",
            "reto_firmado":
            base64.b64encode(self.sig.sign(base64.b64decode(reto)))
        }
        paquete = crea_paquete(auth)
        # envía
        self.socket_connection.send(paquete)
        # import pdb; pdb.set_trace()
        # recibe la respuesta
        self.socket_connection.recv(2)
        d = json.loads(self.socket_connection.recv(1024))
        if not d['ok']:
            print d['detalles']
        return d

    def registro(self):
        """
        genera un mensaje de tipo registro con llaves codificadas en base 64
        :return: diccionario oon la respuesta del servidor
        """
        # adjuntar la pre_llave_firmada correcta

        registro = {
            "tipo": "registro",
            "nombre": self.nombre,
            "llave_identidad": base64.b64encode(self.pk.__bytes__()),
            "llave_identidad_firmar": base64.b64encode(self.vk.__bytes__()),
            # Cifra la llave de medio uso
            "pre_llave_firmada": base64.b64encode(self.medk)
        }

        paquete = crea_paquete(registro)
        # manda por el socket
        self.socket_connection.send(paquete)
        # recibe la respuesta
        self.socket_connection.recv(2)
        resp = json.loads(self.socket_connection.recv(1024))
        if resp["ok"]:
            dicc = {
                "nombre": self.nombre,
                "sk": base64.b64encode(self.sk.__bytes__()),
                "pk": base64.b64encode(self.pk.__bytes__()),
                "sig": base64.b64encode(self.sig.__bytes__()),
                "vk": base64.b64encode(self.vk.__bytes__()),
                "medk_pub": base64.b64encode(self.medk_pub.__bytes__()),
                "medk_priv": base64.b64encode(self.medk_priv.__bytes__()),
                "medk": base64.b64encode(self.medk)
            }

            json.dump(dicc, open("keys_" + self.nombre, "w"))
        else:
            print "Error. El registro fue incorrecto\n" + resp["detalles"]
        return resp

    def solicita_llaves(self, nombre):
        """
        solicita las llaves de un usuario
        :param nombre:
        :return: las llaves en un diccionario o el error
        """
        # Solicita las llaves de usuario con quien se quiere comunicar
        solicitud = {'tipo': "datos_usuario", 'nombre': nombre}
        paquete = crea_paquete(solicitud)
        # envía la solicitud de datos al servidor
        self.socket_connection.send(paquete)
        # recibe la respuesta
        self.socket_connection.recv(2)
        a = self.socket_connection.recv(1024)
        return json.loads(a)

    def crea_sesion_a(self, nombre):
        """
        Se escribe el archivo como nombreA_nombreB_values
        :param nombre: Usuario con quien se desea establecer la comunicación
        :return: devuelve el secreto calculado a partir de las llaves del usuario con el nombre
        especificado
        """
        dicti = self.solicita_llaves(nombre)
        if not dicti["ok"]:
            return "Error:\n" + dicti["detalles"]

        ikb = PublicKey(base64.b64decode(dicti["llave_identidad"]))
        mkb = PublicKey(base64.b64decode(dicti["pre_llave"]))
        # genera la llave efimera
        efk_priv = PrivateKey.generate()
        # calcula el secreto como: DH(IKA,MKB) || DH(EKA, IKB) || DH(EKA,MKB)
        b1 = Box(self.sk, mkb).shared_key()
        b2 = Box(efk_priv, ikb).shared_key()
        b3 = Box(efk_priv, mkb).shared_key()
        secreto = b1 + b2 + b3
        # Genera un diccionario para escribir en un archivo las llaves de Bob
        dicc = {
            'ikb': base64.b64encode(ikb.__bytes__()),
            'mkb': base64.b64encode(mkb.__bytes__()),
            'efk_pub': base64.b64encode(efk_priv.public_key.__bytes__()),
            'secreto': base64.b64encode(secreto),
            'kenv': "",
            'krecib': "",
            "establecida": False,
            "tipo": "A"
        }
        # escribe el archivo
        json.dump(dicc, open(self.nombre + "_" + nombre + "_values", "w"))
        self.secreto = secreto
        return secreto

    def crea_sesion_b(self, nombre, ek, ik):
        """
        Asigna al secreto de este objeto
        :param nombre: con quien se establece la sesión
        :param ek: Llave efímera de Alice publica
        :param ik: Lave pública de Alice publica
        :return: el secreto calculado a partir de las llaves del usuario ek, ik
        """
        ekk = PublicKey(ek)
        ikk = PublicKey(ik)
        # Se calcula DH(MKB, IKA) || DH(IKB,EKA) || DH(MKB,EKA)
        b1 = Box(self.medk_priv, ikk).shared_key()
        b2 = Box(self.sk, ekk).shared_key()
        b3 = Box(self.medk_priv, ekk).shared_key()
        secreto = b1 + b2 + b3
        # Genera un diccionario para escribir en un archivo el secreto para enviar y recibir mensajes con Alice
        dicc = {
            'secreto': base64.b64encode(secreto),
            'kenv': "",
            'krecib': "",
            "establecida": False,
            "tipo": "B"
        }
        # escribe el archivo
        json.dump(dicc, open(self.nombre + "_" + nombre + "_values", "w"))
        self.secreto = secreto
        return secreto

    def envia_mensaje(self, mensaje, nombre_destino, kenviar):
        """
        Envía un mensaje al usuario especificado, si no se ha iniciado una sesion
        también se envía la llave efimera y la llave identidad'''
        :param mensaje: El mensaje al usuario dado, DEBE PASARSE COMO: b'[mensaje]
        :param nombre_destino: Nombre de usuario al que se desea enviar el mensaje
        :param kenviar: La llave actual del mensaje a cifrar
        :return: Diccionario con la respuesta del servidor
        """

        # cifra el mensaje
        sbox = SecretBox(kenviar)
        msj = sbox.encrypt(mensaje)
        # Se lee el archivo entre los usuarios
        data = json.load(
            open(self.nombre + "_" + nombre_destino + "_values", "r"))
        establecida = data["establecida"]
        # genera el paq. de datos a enviar
        if not establecida:
            llave_efimera = data["efk_pub"]
            paq = {
                "tipo": "msj",
                "nombre_destino": nombre_destino,
                "mensaje": base64.b64encode(msj),
                "llave_efimera": llave_efimera,
                "llave_identidad": base64.b64encode(self.pk.__bytes__())
            }
        else:
            paq = {
                "tipo": "msj",
                "nombre_destino": nombre_destino,
                "mensaje": base64.b64encode(msj)
            }

        paquete = crea_paquete(paq)
        # envía el msj al servidor
        self.socket_connection.send(paquete)
        self.socket_connection.recv(2)
        return self.socket_connection.recv(1024)

    def dame_mensajes(self):
        """
        Pide los mensajes al servidor
        :return: Json con los mensajes que el servidor tiene para éste usuario
        """
        paq = {'tipo': "dame_mensajes"}
        paquete = crea_paquete(paq)
        self.socket_connection.send(paquete)

        # recibe la respuesta
        self.socket_connection.recv(2)
        d = json.loads(
            self.socket_connection.recv(65536))  # Valor máximo provisional
        if d["ok"]:
            return d
        else:
            return "ERROR " + d["detalles"]

    def genera_kenviar_krecibir(self, secreto, alice):
        """
        Genera el par de llaves kenviar y krecibir a partir de un secerto
        Asigna los valores correspondientes al objeto
        :param alice: True si eres alice, false e.o.c
        :param secreto: El secreto en comun entre A y B para cifrar los mensajes
        :return: una lista con kenviar y krecibir en este orden
        """
        hash_val = sha512(secreto, encoder=RawEncoder)
        if alice:
            self.kenv = hash_val[:32]
            self.krecib = hash_val[-32:]
        else:
            self.kenv = hash_val[-32:]
            self.krecib = hash_val[:32]
        return hash_val[:32], hash_val[-32:]

    def deriva_kllave(self, kllave, is_kenviar):
        """
        devuelve una la siguiente kllave a partir de aplicar sha256 a una kllave
        :param kllave: Kenviar o krecibir, llaves de 32 bytes
        :param is_kenviar: true si es kenviar, flase en caso contrario
        :return: la siguiente kenviar o krecibir de acuerdo a la entrada
        """
        llave = sha256(kllave, encoder=RawEncoder)
        if is_kenviar:
            self.kenv = llave
        else:
            self.krecib = llave
        return llave

    def descifra_mensaje(self, mensaje):
        """
        Descrifra un mensaje con una Sbox
        :param mensaje: mensaje cifrado en base 64 y con Sbox
        :return: el mensaje descifrado
        """
        sb = SecretBox(self.krecib)
        dec = sb.decrypt(base64.b64decode(mensaje))
        return dec

    def cerrar_conexion(self):
        return self.socket_connection.close()