Canales de Comunicacion - parte 2 HTTP cifrado

Ejercicio

Cambiar al branch que posee los métodos no implementados

$ git checkout encrypted-http

Creación de listener con las flags necesarias para realizar la conexión con el agente

$ curl localhost:5000/listeners/ -d '{"type": "http", "bind_host": "127.0.0.1", "bind_port": 8080, "target_host": "127.0.0.1", "target_port": 8080, "sym_key": "c29tZSByYW5kb20ga2V5IQ=="}' -H 'Content-Type: application/json'

Recolectar el tráfico necesario para analizar la conexión entre el agente y el listener

$ sudo tcpdump -A -s 0 'tcp port 8080 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' -i lo

Librerías a utilizar

ECDSA

This is an easy-to-use implementation of ECDSA cryptography (Elliptic Curve Digital Signature Algorithm), implemented purely in Python, released under the MIT license. With this library, you can quickly create keypairs (signing key and verifying key), sign messages, and verify the signatures. The keys and signatures are very short, making them easy to handle and incorporate into other protocols.

from ecdsa import SigningKey
sk = SigningKey.generate() # uses NIST192p
vk = sk.verifying_key
signature = sk.sign(b"message")
assert vk.verify(signature, b"message")

Templates

DHHandler

import json
from typing import Mapping, Optional
from base64 import b64encode, b64decode

from . import Handler, AuthenticatedHandler
from malon_lp.crypto.dh import KeyExchange, get_client_id
from malon_lp.crypto.sym import SymmetricCipher



KeyRespository = Mapping[str, bytes]


class DHHandler(Handler):
    def __init__(self, ke: KeyExchange, handler: AuthenticatedHandler, kr: Optional[KeyRespository] = None):
        self._ke = ke
        self._handler = handler
        self._kr = kr if kr is not None else {} # en caso de no proveer un KeyRepository crea un diccionario
    
    def _handle_handshake_msg(self, public_key: bytes) -> bytes:
        """
            Recibe la clave publica del cliente, y la persiste en el KeyRepository.
            Al finalizar le retorna al cliente la clave publica del Listener.
        """
        client_id = get_client_id(public_key).hex()
        self._kr[client_id] = public_key
        response_msg = {
            'handshake_msg': {
                'public_key': b64encode(self._ke.get_public_key()).decode('utf-8')
            }
        }
        return json.dumps(response_msg).encode('utf-8')
    
    def _handle_client_msg(self, client_id: str, encrypted_payload: bytes) -> bytes:
        """
            - Obtiene la clave publica del KeyRepository a partir del client_id # self._kr.get(client_id)
            - Genera la clave compartida # self._ke.get_shared_key(pub_key)
            - Verifica y decifra el mensaje con la misma
            - Delega el mensaje en el AuthenticatedHandler para obtener la respuesta para el cliente
            - La cifra y firma la respuesta con la clave compartida
            - Encodea el payload cifrado en base64
            - Devuelve la respuesta con el formato  b'{"server_msg": {"payload": "cHVjYXJhCg==" } }'
        """
        raise NotImplementedError

    def handle_msg(self, msg: bytes) -> bytes:
        """
            realiza un dispatch de los mensajes recibido, segun corresponda
            ver:
                -_handle_handshake_msg {"handshake_msg":{"public_key": "..."}}
                -_handle_client_msg {"client_msg":{"client_id": "...", "payload": "..."}}
        """
        base_msg = json.loads(msg.decode('utf-8'))
        if base_msg.get('handshake_msg') is not None:
            return self._handle_handshake_msg(b64decode(base_msg['handshake_msg']['public_key']))
        elif base_msg.get('client_msg') is not None:
            return self._handle_client_msg(
                base_msg['client_msg']['client_id'],
                b64decode(base_msg['client_msg']['payload'])
            )
        else:
            raise RuntimeError('Unexpected message type')

EncryptedHandler

from typing import Optional
from . import Handler

from malon_lp.crypto.sym import SymmetricCipher

class EncryptedHandler(Handler):
    KEY_LENGTH = 16

    def __init__(self, key: bytes, handler: Handler):
        if len(key) != self.KEY_LENGTH:
            raise RuntimeError('Invalid key length, should be {}'.format(self.KEY_LENGTH))
        
        self._cipher = SymmetricCipher(key)
        self._handler = handler
    
    def handle_msg(self, msg: bytes) -> bytes:
        """
            Delega el mensaje descfirado (por la primer capa de criptografia simetrica)
            en el Handler siguiente.

            - se debe verificar y descifrar el mensaje
            - delegar el mensaje al Handler siguiente
            - finalmente se debe cifrar y firmar el mensaje, para poder devolverlo
        """
        raise NotImplementedError

Última actualización