Exemple #1
0
    def send_authentication(self, remote_node):
        """
        1. initiator generates ecdhe-random and nonce and creates auth
        2. initiator connects to remote and sends auth

        Handshake for connecting to Known Peer
        eciesEncrypt(remote-pubk, sign(privkey, token^nonce) || 0x80 || ecdhe-random || nonce )

        Handshake for connecting to New Peer
        eciesEncrypt(remote-pubk, sign(privkey, nonce) || 0x80 || ecdhe-random || nonce )

        The value 0x80 is a placeholder which maybe used in the future for versioning and/or
        protocol handshake.
        """
        self.ephemeral_ecc = ECCx()  # FIXME, add seed
        ecdhe_pubkey = self.ephemeral_ecc.get_pubkey()
        assert len(ecdhe_pubkey) == 512 / 8
        token = remote_node.token
        nonce = ienc(random.randint(0, 2**256 - 1))
        assert len(nonce) == 32
        token_or_nonce = token or nonce
        signature = self.node.sign(ienc(token_or_nonce))
        assert len(signature) == 65
        payload = signature + '0x80' + ecdhe_pubkey + token_or_nonce
        auth_message = crypto.encrypt(payload, remote.pubkey)
        self.peer.send(auth_message)
        self._authentication_sent = True
Exemple #2
0
 def dump_Peers(self, peers):
     """
     :param peers: a sequence of (ip, port, pid)
     :return: None if no peers
     """
     data = [self.cmd_map_by_name["Peers"]]
     for ip, port, pid in peers:
         ip = list((ienc(int(x)) for x in ip.split(".")))
         data.append([ip, port, pid])
     return self.dump_packet(data)
Exemple #3
0
def list_ienc(lst):
    "recursively big endian encode all integers in a list"
    nlst = []
    for i, e in enumerate(lst):
        if isinstance(e, list):
            nlst.append(list_ienc(e))
        elif isinstance(e, int):
            nlst.append(ienc(e))
        else:
            nlst.append(e)
    return nlst
Exemple #4
0
    def receive_authentication(self, other, ciphertext):
        """
        Verification (function, upon receive of PresetAuthentication):
        3. remote generates ecdhe-random and nonce and creates auth
        4. remote receives auth and decrypts (ECIES performs authentication before
        decryption)
            - If address is known, lookup token and public key to be authenticated
            - derive signature-message = sha3(token || addr^addrRemote)
            - success -> AcknowledgeAuthentication
        5. remote sends auth
        6. remote derives shared-secret, aes-secret, mac-secret, ingress-mac, egress-mac
"""

        # eciesEncrypt(remote-pubk, sign(privkey, token^nonce) || 0x80 || ecdhe-random || nonce )

        data = self.node.decrypt(ciphertext)
        assert len(data) == 64 + 1 + 64 + 32
        signature = data[:65]
        assert data[65] == '0x80'
        remote_ecdhe_pubkey = data[65:65 + 64]
        token_or_nonce = idec(data[-32:])

        # verify signature
        if not self.node.verify(signature, token_or_nonce):
            return self.disconnect()

        # recover remote pubkey
        remote_pubkey = ecdsa_recover(token_or_nonce, signature)

        # lookup pubkey and related token
        token_database = dict()  # FIXME
        token = token_database.get(remote_pubkey, None)
        if token and token != token_or_nonce:
            # something fishy
            # FIXME reset node reputation
            pass

        remote_nonce = token_or_nonce

        # send authentication if not yet
        if not self._authentication_sent:
            remote_node = RemoteNode(remote_pubkey)  # FIXME LOOKUP
            self.send_authentication(remote_node)

            # - success -> AcknowledgeAuthentication
            self.acknowledge_authentication(other, remote_pubkey,
                                            remote_ecdhe_pubkey)

        # ecdhe_shared_secret = ecdh.agree(ecdhe-random, ecdhe-random-public)
        # Compute public key with the local private key and return a 512bits shared key
        ecdhe_shared_secret = self.ephemeral_ecc.get_ecdh_key(remote_pubkey)
        ecdhe_pubkey = ephemeral_ecc.get_pubkey()
        # shared-secret = sha3(ecdhe-shared-secret || sha3(nonce || remote-nonce))
        shared_secret = sha3(ecdhe_shared_secret +
                             sha3(ienc(self.nonce) + ienc(remote_nonce)))

        self.aes_secret = sha3_256(ecdhe_shared_secret + shared_secret)
        self.mac_secret = sha3_256(ecdhe_shared_secret + self.aes_secret)
        # egress-mac = sha3(mac-secret^nonce || auth)
        self.egress_mac = sha3_256(
            sxor(self.mac_secret, self.nonce) + ciphertext)
        # ingress-mac = sha3(mac-secret^remote-nonce || auth)
        self.ingress_mac = sha3_256(
            sxor(self.mac_secret, remote_nonce) + ciphertext)
        self.token = sha3(shared_secret)

        iv = pyelliptic.Cipher.gen_IV('aes-256-ctr')
        self.aes_enc = pyelliptic.Cipher(self.aes_secret,
                                         iv,
                                         1,
                                         ciphername='aes-256-ctr')
        self.aes_dec = pyelliptic.Cipher(self.aes_secret,
                                         iv,
                                         0,
                                         ciphername='aes-256-ctr')

        self.is_ready = True