def _step_2_password_verification(self, sock, password, salt):
     """
     Verify password.
     :param sock:
     :param password:
     :param salt:
     :return:
     """
     pw_hash = self.crypto_service.compute_pw_hash(password, salt)
     nonce = PacketOrganiser.genRandomNumber()
     msg = PacketOrganiser.prepare_packet(pw_hash, nonce)
     auth_2_msg = self.crypto_service.sym_encrypt(self.dh_key, msg)
     sock.sendto(auth_2_msg, self.server_addr)
     # step 3
     recv_msg = util.get_one_response(sock, self.server_addr)
     # print("Receive msg from {}: {}".format(self.server_addr, recv_msg))
     dec_msg = self.crypto_service.sym_decrypt(self.dh_key, recv_msg)
     n, msg_parts = PacketOrganiser.process_packet(dec_msg)
     if n != nonce:
         raise Exception(c.STEP_THREE_NONCE_FAIL_MSG)
     auth_result = msg_parts[0]
     if auth_result == c.AUTH_SUCCESS:
         self.auth_success = True
     elif auth_result == c.MSG_RESPONSE_WRONG_CR:
         print(c.WRONG_CR_MSG)
     return self.auth_success
Esempio n. 2
0
 def _step_2_password_verification(self, sock, password, salt):
     """
     Verify password.
     :param sock:
     :param password:
     :param salt:
     :return:
     """
     pw_hash = self.crypto_service.compute_pw_hash(password, salt)
     nonce = PacketOrganiser.genRandomNumber()
     msg = PacketOrganiser.prepare_packet(pw_hash, nonce)
     auth_2_msg = self.crypto_service.sym_encrypt(self.dh_key, msg)
     sock.sendto(auth_2_msg, self.server_addr)
     # step 3
     recv_msg = util.get_one_response(sock, self.server_addr)
     # print("Receive msg from {}: {}".format(self.server_addr, recv_msg))
     dec_msg = self.crypto_service.sym_decrypt(self.dh_key, recv_msg)
     n, msg_parts = PacketOrganiser.process_packet(dec_msg)
     if n != nonce:
         raise Exception(c.STEP_THREE_NONCE_FAIL_MSG)
     auth_result = msg_parts[0]
     if auth_result == c.AUTH_SUCCESS:
         self.auth_success = True
     elif auth_result == c.MSG_RESPONSE_WRONG_CR:
         print(c.WRONG_CR_MSG)
     return self.auth_success
 def _authenticate_and_send_msg(self, username, chat_msg):
     # start peer authentication
     nonce = util.get_good_nonce(self.request_cache)
     new_auth = ClientClientAuthentication(username, self.auth.crypto_service, chat_msg)
     new_auth.timestamp = PacketOrganiser.get_new_timestamp()  # timestamp when created, for packet resend
     key = self.auth.dh_key
     msg_to_send = PacketOrganiser.prepare_packet([c.MSG_TYPE_START_NEW_CHAT, username, ""], nonce=nonce)
     util.add_to_request_cache(
         self.request_cache, nonce, c.MSG_TYPE_START_NEW_CHAT, key, msg_to_send, self.auth.server_addr, new_auth
     )  # add to cache
     return username, self.auth.server_addr, self.serv.sym_encrypt(key, msg_to_send)
    def handle(self):
        """
        Handle requests from the clients.
        :return:
        """
        global auth_dict, nonce_dict, crypto_service, password_hash_dict, user_addr_dict, chatting_service
        msg = self.request[0]
        sock = self.request[1]
        # get auth instance for client
        if self.client_address not in auth_dict:
            try:
                _, msg_parts = PacketOrganiser.process_packet(msg)
            except:
                return
            if msg_parts[0] != c.GREETING:
                return
            # new client, create an auth entry in the auth dictionary
            auth_dict[self.client_address] = Authentication(
                self.client_address, crypto_service, password_hash_dict)
        else:
            auth = auth_dict[self.client_address]
            if not PacketOrganiser.isValidTimeStampSeconds(
                    auth.timestamp, c.KEEP_ALIVE_TIME):
                auth_dict.pop(self.client_address)

        cur_auth = auth_dict[self.client_address]
        assert isinstance(cur_auth, Authentication)
        rep = None
        if not cur_auth.is_auth():
            rep = cur_auth.process_request(msg, user_addr_dict)

        else:
            # get decrypted msg
            dec_msg = crypto_service.sym_decrypt(cur_auth.dh_key, msg)
            n, msg_ps = PacketOrganiser.process_packet(dec_msg)
            auth_dict[
                self.
                client_address].timestamp = PacketOrganiser.get_new_timestamp(
                )  # update timestamp
            rep = chatting_service.get_response(self.client_address, msg_ps)
            if rep is not None:
                rep = PacketOrganiser.prepare_packet(rep, n)
                rep = crypto_service.sym_encrypt(cur_auth.dh_key, rep)

        try:
            if rep is not None:
                sys.stdout.flush()
                sock.sendto(rep, self.client_address)
            elif cur_auth.is_auth():
                cur_auth.loginfailures += 1
        except socket.error:
            print(c.FAIL_MSG_FWD)
            return
    def handle(self):
        """
        Handle requests from the clients.
        :return:
        """
        global auth_dict, nonce_dict, crypto_service, password_hash_dict, user_addr_dict, chatting_service
        msg = self.request[0]
        sock = self.request[1]
        # get auth instance for client
        if self.client_address not in auth_dict:
            try:
                _, msg_parts = PacketOrganiser.process_packet(msg)
            except:
                return
            if msg_parts[0] != c.GREETING:
                return
            # new client, create an auth entry in the auth dictionary
            auth_dict[self.client_address] = Authentication(self.client_address, crypto_service,
                                                                           password_hash_dict)
        else:
            auth = auth_dict[self.client_address]
            if not PacketOrganiser.isValidTimeStampSeconds(auth.timestamp,c.KEEP_ALIVE_TIME):
                auth_dict.pop(self.client_address)

        cur_auth = auth_dict[self.client_address]
        assert isinstance(cur_auth, Authentication)
        rep = None
        if not cur_auth.is_auth():
            rep = cur_auth.process_request(msg, user_addr_dict)

        else:
            # get decrypted msg
            dec_msg = crypto_service.sym_decrypt(cur_auth.dh_key, msg)
            n, msg_ps = PacketOrganiser.process_packet(dec_msg)
            auth_dict[self.client_address].timestamp = PacketOrganiser.get_new_timestamp()  # update timestamp
            rep = chatting_service.get_response(self.client_address, msg_ps)
            if rep is not None:
                rep = PacketOrganiser.prepare_packet(rep, n)
                rep = crypto_service.sym_encrypt(cur_auth.dh_key, rep)

        try:
            if rep is not None:
                sys.stdout.flush()
                sock.sendto(rep, self.client_address)
            elif cur_auth.is_auth():
                cur_auth.loginfailures += 1
        except socket.error:
            print(c.FAIL_MSG_FWD)
            return
 def _step_0_get_challenge(self, sock):
     """
     Challenge step.
     :param sock:
     :return:
     """
     # send greeting to the server
     # print("Get Username: {}, Password: {}".format(username, password))
     msg_to_send = PacketOrganiser.prepare_packet(c.GREETING, add_time=False)
     sock.sendto(msg_to_send, self.server_addr)
     recv_msg = util.get_one_response(sock, self.server_addr)
     # print("Receive msg from {}: {}".format(self.server_addr, recv_msg))
     _, recv_msg_parts = PacketOrganiser.process_packet(recv_msg)
     # chl, k, ind = recv_msg_parts
     return recv_msg_parts
    def run(self):
        """
        A new thread for resending any message in the cache.
        This thread also sends keep-alive messages every thirty seconds.
        """
        global addr_auths, user_addr_dict, active_users
        i = 0
        while self.resending:
            time.sleep(c.RESEND_SLEEP_SEC)
            i = i + c.TIME_STEP
            if i == c.KEEP_ALIVE_INTERVAL:
                i = 0
                self.send_keep_alive()
            caches_to_remove = []
            for nonce, cache in self.request_cache.iteritems():
                ts = cache[c.CACHE_TS_IND]
                if not PacketOrganiser.isValidTimeStamp(ts, c.TS_RESEND_MICRO_SEC):
                    if not self.resend(cache):
                        caches_to_remove.append(nonce)

            for n in caches_to_remove:
                cache_to_remove = self.request_cache.pop(n)
                # also remove addr_auths entry
                addr = cache_to_remove[c.CACHE_ADDR_IND]
                if addr in addr_auths:
                    auth_to_delete = addr_auths.pop(addr)
                    user_addr_dict.pop(auth_to_delete.username)
                    active_users.pop(auth_to_delete.username)
Esempio n. 8
0
 def _step_0_get_challenge(self, sock):
     """
     Challenge step.
     :param sock:
     :return:
     """
     # send greeting to the server
     # print("Get Username: {}, Password: {}".format(username, password))
     msg_to_send = PacketOrganiser.prepare_packet(c.GREETING,
                                                  add_time=False)
     sock.sendto(msg_to_send, self.server_addr)
     recv_msg = util.get_one_response(sock, self.server_addr)
     # print("Receive msg from {}: {}".format(self.server_addr, recv_msg))
     _, recv_msg_parts = PacketOrganiser.process_packet(recv_msg)
     # chl, k, ind = recv_msg_parts
     return recv_msg_parts
    def run(self):
        """
        A new thread for resending any message in the cache.
        This thread also sends keep-alive messages every thirty seconds.
        """
        global addr_auths, user_addr_dict, active_users
        i = 0
        while self.resending:
            time.sleep(c.RESEND_SLEEP_SEC)
            i = i + c.TIME_STEP
            if i == c.KEEP_ALIVE_INTERVAL:
                i = 0
                self.send_keep_alive()
            caches_to_remove = []
            for nonce, cache in self.request_cache.iteritems():
                ts = cache[c.CACHE_TS_IND]
                if not PacketOrganiser.isValidTimeStamp(
                        ts, c.TS_RESEND_MICRO_SEC):
                    if not self.resend(cache):
                        caches_to_remove.append(nonce)

            for n in caches_to_remove:
                cache_to_remove = self.request_cache.pop(n)
                # also remove addr_auths entry
                addr = cache_to_remove[c.CACHE_ADDR_IND]
                if addr in addr_auths:
                    auth_to_delete = addr_auths.pop(addr)
                    user_addr_dict.pop(auth_to_delete.username)
                    active_users.pop(auth_to_delete.username)
 def send_keep_alive(self):
     """
     Sends a keep alive message to the server.
     """
     global server_auth
     res_msg = PacketOrganiser.prepare_packet(c.MSG_TYPE_KEEP_ALIVE)
     encrypt_msg = server_auth.crypto_service.sym_encrypt(server_auth.dh_key, res_msg)
     self.sock.sendto(encrypt_msg, server_auth.server_addr)
 def send_keep_alive(self):
     """
     Sends a keep alive message to the server.
     """
     global server_auth
     res_msg = PacketOrganiser.prepare_packet(c.MSG_TYPE_KEEP_ALIVE)
     encrypt_msg = server_auth.crypto_service.sym_encrypt(
         server_auth.dh_key, res_msg)
     self.sock.sendto(encrypt_msg, server_auth.server_addr)
def replace_ts_in_msg(msg):
    """

    :param msg:
    :return:
    """
    msg_without_ts = msg[:-c.TS_LEN]
    new_msg = msg_without_ts + PacketOrganiser.get_new_timestamp()
    return new_msg
def replace_ts_in_msg(msg):
    """

    :param msg:
    :return:
    """
    msg_without_ts = msg[:-c.TS_LEN]
    new_msg = msg_without_ts + PacketOrganiser.get_new_timestamp()
    return new_msg
def display_user_message(raw_msg, username):
    """

    :param raw_msg:
    :param username:
    :return:
    """
    ts = PacketOrganiser.get_new_timestamp()
    msg = "{} <{}>: {}".format(username, ts, raw_msg)
    cmd_output(msg)
def display_user_message(raw_msg, username):
    """

    :param raw_msg:
    :param username:
    :return:
    """
    ts = PacketOrganiser.get_new_timestamp()
    msg = "{} <{}>: {}".format(username, ts, raw_msg)
    cmd_output(msg)
def send_confirmation(sock, crypto_service, key, n, r_addr, second_part=None):

    if second_part:
        conf_msg_parts = [c.MSG_RESPONSE_OK, second_part, ""]
    else:
        conf_msg_parts = c.MSG_RESPONSE_OK

    conf_msg = PacketOrganiser.prepare_packet(conf_msg_parts, n)
    enc_conf_msg = crypto_service.sym_encrypt(key, conf_msg)
    sock.sendto(enc_conf_msg, r_addr)
def send_confirmation(sock, crypto_service, key, n, r_addr, second_part=None):

    if second_part:
        conf_msg_parts = [c.MSG_RESPONSE_OK, second_part, ""]
    else:
        conf_msg_parts = c.MSG_RESPONSE_OK

    conf_msg = PacketOrganiser.prepare_packet(conf_msg_parts, n)
    enc_conf_msg = crypto_service.sym_encrypt(key, conf_msg)
    sock.sendto(enc_conf_msg, r_addr)
 def _stage_0_generate_challenge(self):
     """
     Generate and send challenge to client
     :return:
     """
     # sent a challenge to client
     chl, ind, self.masksize = self.ra.get_challenge_tupple(self.loginfailures)
     self.stage = c.AUTH_STAGE_1
     msg_to_send_parts = [chl, self.masksize, ind]
     msg_to_send = PacketOrganiser.prepare_packet(msg_to_send_parts, add_time=False)
     return msg_to_send
 def _handle_single_cmd(self, msg_type):
     """
     :param msg_type: the type of the message
     :return: Prepares and returns the encrypted message depending on the message type
     """
     nonce = util.get_good_nonce(self.request_cache)
     res_msg = PacketOrganiser.prepare_packet(msg_type, nonce)
     util.add_to_request_cache(
         self.request_cache, nonce, msg_type, self.auth.dh_key, res_msg, self.auth.server_addr
     )  # add to cache
     return msg_type, self.auth.server_addr, self.serv.sym_encrypt(self.auth.dh_key, res_msg)
 def handle_start_new_chat(self, a_addr, b_username):
     """
     b_addr, k_ab, ttb, ts, n1
     :param a_addr: Chat requesting client address
     :param b_addr: Address of client wanting to chat with
     :return: The server sends as response the ticket to b and a symettric key to talk to b.
     """
     k_ab = self.auth_dict[a_addr].crypto_service.new_sym_key()
     a_username = self.auth_dict[a_addr].username
     b_addr = self.user_addr_dict[b_username]
     auth = self.auth_dict[b_addr]
     if not PacketOrganiser.isValidTimeStampSeconds(auth.timestamp,
                                                    c.KEEP_ALIVE_TIME):
         self.auth_dict.pop(b_addr)
         return c.ERR_CLIENT_DOWN
     k_b = self.auth_dict[b_addr].dh_key
     ttb = PacketOrganiser.prepare_packet(
         [a_username, util.addr_to_str(a_addr), k_ab])
     enc_ttb = self.crypto_service.sym_encrypt(k_b, ttb)
     signed_enc_ttb = enc_ttb + self.crypto_service.rsa_sign(enc_ttb)
     return [util.addr_to_str(b_addr), k_ab, signed_enc_ttb]
    def resend(self, cache):
        """
        :param cache: The parameter cache stores what message haven't acknowledged to resend them.
        :return: True if resend happened, False otherwise
        """
        global server_auth
        # first check if the cache is more than 30 seconds old
        # if it is, we will drop the cache entry, which means the other side is off line, don't resend again
        if cache[c.CACHE_TYPE_IND] == c.MSG_TYPE_MSG:
            original_ts = self.get_original_ts(cache)
            if not PacketOrganiser.isValidTimeStampSeconds(original_ts, c.RESEND_TIMEOUT):
                util.cmd_output(c.WARNING_STOP_RESENDING)
                return False

        ts = PacketOrganiser.get_new_timestamp()
        cache[c.CACHE_TS_IND] = ts
        msg = util.replace_ts_in_msg(cache[c.CACHE_MSG_IND])
        # cache[c.CACHE_MSG_IND] = msg
        enc_msg = server_auth.crypto_service.sym_encrypt(cache[c.CACHE_KEY_IND], msg)
        self.sock.sendto(enc_msg, cache[c.CACHE_ADDR_IND])
        return True
Esempio n. 22
0
 def __init__(self, addr, remote_addr, crypto_service):
     assert isinstance(crypto_service, CryptoService)
     self.crypto_service = crypto_service
     self.addr = addr
     self.timestamp = time.time()
     self.ra = RequestAuthority.RequestAuthority()
     self.stage = 0
     self.dh_key = 0
     self.server_addr = remote_addr
     self.auth_success = False
     self.packetgen = PacketOrganiser()
     self.username = None
 def handle_list(self):
     """
     :return: Handles the list input and sends the list of active users as response.
     """
     res = ""
     for user, addr in self.user_addr_dict.iteritems():
         auth = self.auth_dict[addr]
         if not PacketOrganiser.isValidTimeStampSeconds(
                 auth.timestamp, c.KEEP_ALIVE_TIME):
             self.auth_dict.pop(addr)
             continue
         res += user + ","
     return [c.MSG_TYPE_LIST, res[:-1], ""]
 def _stage_2_pw_check(self, request, user_addr_dict):
     """
     Stage 2 is to check if the password is correct
     :param request: Request is the incoming message which contains the password.
     :param user_addr_dict: The user_add_dict is the dictionary which has each user and associated address stored.
     :return: The method returns a encrypted response message
     """
     # decrypt the message and check the password hash
     dec_request = self.crypto_service.sym_decrypt(self.dh_key, request)
     n, request_parts = PacketOrganiser.process_packet(dec_request)
     pw_hash = request_parts[0]
     if pw_hash != self.pw_dict[self.username][0]:
         msg = PacketOrganiser.prepare_packet(c.MSG_RESPONSE_WRONG_CR, nonce=n)
         enc_msg = self.crypto_service.sym_encrypt(self.dh_key, msg)
         self.stage = c.AUTH_STAGE_INIT
         self.loginfailures += 1
     else:
         msg = PacketOrganiser.prepare_packet(c.AUTH_SUCCESS, nonce=n)
         enc_msg = self.crypto_service.sym_encrypt(self.dh_key, msg)
         self.stage = c.AUTH_STAGE_FINISHED
         user_addr_dict[self.username] = self.addr
     return enc_msg
 def _send_msg(self, username, chat_msg):
     # send the message to user
     addr = self.user_addr_dict[username]
     auth = self.addr_auths[addr]
     key = auth.dh_key
     nonce = util.get_good_nonce(self.request_cache)
     auth.last_nonce = nonce
     hmac = CryptoService.generate_hmac_sign(key, chat_msg)
     chat_msg_hmac = chat_msg + hmac  # add HMAC to chat_msg
     msg_to_send = PacketOrganiser.prepare_packet([c.MSG_TYPE_MSG, chat_msg_hmac, ""], nonce=nonce)
     encrypt_msg = self.serv.sym_encrypt(key, msg_to_send)
     util.add_to_request_cache(self.request_cache, nonce, c.MSG_TYPE_MSG, key, msg_to_send, addr)  # add to cache
     return None, addr, encrypt_msg
Esempio n. 26
0
 def __init__(self, username, crypto_service, first_msg=None):
     assert isinstance(crypto_service, CryptoService)
     self.crypto_service = crypto_service
     self.timestamp = time.time()
     self.ra = RequestAuthority()
     self.stage = 0
     self.dh_key = 0
     self.pri_key = 0
     self.auth_success = False
     self.packetgen = PacketOrganiser()
     self.first_msg = first_msg  # message initialize the C/C authentication
     self.last_nonce = None
     self.username = username
    def resend(self, cache):
        """
        :param cache: The parameter cache stores what message haven't acknowledged to resend them.
        :return: True if resend happened, False otherwise
        """
        global server_auth
        # first check if the cache is more than 30 seconds old
        # if it is, we will drop the cache entry, which means the other side is off line, don't resend again
        if cache[c.CACHE_TYPE_IND] == c.MSG_TYPE_MSG:
            original_ts = self.get_original_ts(cache)
            if not PacketOrganiser.isValidTimeStampSeconds(
                    original_ts, c.RESEND_TIMEOUT):
                util.cmd_output(c.WARNING_STOP_RESENDING)
                return False

        ts = PacketOrganiser.get_new_timestamp()
        cache[c.CACHE_TS_IND] = ts
        msg = util.replace_ts_in_msg(cache[c.CACHE_MSG_IND])
        # cache[c.CACHE_MSG_IND] = msg
        enc_msg = server_auth.crypto_service.sym_encrypt(
            cache[c.CACHE_KEY_IND], msg)
        self.sock.sendto(enc_msg, cache[c.CACHE_ADDR_IND])
        return True
Esempio n. 28
0
    def start_authenticate(self, sock, auth_info, a_username):
        """

        :param sock:
        :param auth_info: [b_addr, k_ab, ttb]
        :return:
        """
        b_addr = util.str_to_addr(auth_info[0])
        k_ab = auth_info[1]
        ttb = auth_info[2]

        # ttb, k_ab{a, pub_key, ts}
        self.pri_key = self.crypto_service.get_dh_pri_key()
        self.dh_key = k_ab
        pub_key = self.crypto_service.get_dh_pub_key(self.pri_key)
        inside_msg_parts = [a_username, pub_key, ""]
        inside_msg = PacketOrganiser.prepare_packet(inside_msg_parts)
        enc_inside_msg = self.crypto_service.sym_encrypt(k_ab, inside_msg)

        msg_parts = [ttb, enc_inside_msg, ""]
        pack_to_send = PacketOrganiser.prepare_packet(msg_parts)
        # send the hello message to the other client
        sock.sendto(pack_to_send, b_addr)
        return b_addr
def add_to_request_cache(cache, nonce, type, key, msg, addr, auth=None):
    """

    :param cache:
    :param nonce:
    :param type:
    :param key:
    :param msg:
    :param addr:
    :param auth:
    :return:
    """
    if nonce in cache:
        raise Exception(c.WARNING_EXISTED_NONCE)
    cache[nonce] = [type, key, msg, addr, PacketOrganiser.get_new_timestamp()]
    if auth:
        cache[nonce].append(auth)
def add_to_request_cache(cache, nonce, type, key, msg, addr, auth=None):
    """

    :param cache:
    :param nonce:
    :param type:
    :param key:
    :param msg:
    :param addr:
    :param auth:
    :return:
    """
    if nonce in cache:
        raise Exception(c.WARNING_EXISTED_NONCE)
    cache[nonce] = [type, key, msg, addr, PacketOrganiser.get_new_timestamp()]
    if auth:
        cache[nonce].append(auth)
Esempio n. 31
0
    def _step_1_dh_key_establish(self, sock, chl, k, ind, username):
        """
        DH contribution exchange
        :param sock:
        :param chl:
        :param k:
        :param ind:
        :return:
        """
        ans = self.ra.compute_answer(chl, k)
        dh_pri_key = self.crypto_service.get_dh_pri_key()
        dh_pub_key = self.crypto_service.get_dh_pub_key(dh_pri_key)
        msg_to_send_parts = [dh_pub_key, username, ""]
        nonce = PacketOrganiser.genRandomNumber()
        msg_to_send = PacketOrganiser.prepare_packet(msg_to_send_parts,
                                                     nonce=nonce,
                                                     add_time=False)
        enc_msg_to_send = self.crypto_service.rsa_encrypt(msg_to_send)
        auth_1_msg_parts = [ans, ind, enc_msg_to_send]
        auth_1_msg = PacketOrganiser.prepare_packet(auth_1_msg_parts,
                                                    add_time=False)
        sock.sendto(auth_1_msg, self.server_addr)

        recv_msg = util.get_one_response(sock, self.server_addr)
        # print("Receive msg from {}, length: {}".format(self.server_addr, len(recv_msg)))
        _, msg_sign = PacketOrganiser.process_packet(recv_msg)

        if msg_sign[0] == c.MSG_RESPONSE_WRONG_CR:
            print(c.WRONG_CR_MSG)
            return
        elif msg_sign[0] == c.MSG_RESPONSE_USER_EXISTS:
            print(c.USER_ALREADY_LOGIN_MSG)
            return
        else:
            msg, sign, _ = msg_sign
            if not self.crypto_service.rsa_verify(msg,
                                                  sign):  # TODO for testing
                raise Exception(c.STEP_ONE_FAIL_MSG)
            _, pub_enc_salt = PacketOrganiser.process_packet(msg)
            other_pub_key, enc_salt, _ = pub_enc_salt
            other_pub_key = int(other_pub_key)
            self.dh_key = self.crypto_service.get_dh_secret(
                dh_pri_key, other_pub_key)
            dec_salt_pack = self.crypto_service.sym_decrypt(
                self.dh_key, enc_salt)
            n1, salt_parts = PacketOrganiser.process_packet(dec_salt_pack)
            salt = salt_parts[0]

            if n1 == nonce:
                return salt
    def _stage_1_dh_key_exchange(self, request, user_addr_dict):
        """
        check the challenge answer, decrypt the client DH public key and send DH public key back
        :param request: request from client
        :param user_addr_dict: dictionary which keep tracking of the username and corresponding IP address and port
        :return:
        """
        try:
            _, request_parts = PacketOrganiser.process_packet(request)
            c_ans, ind, enc_client_msg = request_parts
        except:
            return None
        c_ans = int(c_ans)
        ind = int(ind)
        #k = self.ra.getMaskSize()  # TODO flaw when mask size changed
        if self.ra.challengeComm.is_challenge_matched(self.masksize, ind, c_ans):
            dec_msg = self.crypto_service.rsa_decrypt(enc_client_msg)
            n1, dec_msg_parts = PacketOrganiser.process_packet(dec_msg)
            dec_dh_pub_client, username, _ = dec_msg_parts
            if username in user_addr_dict:  # prevent duplicate login
                self.stage = c.AUTH_STAGE_INIT
                return PacketOrganiser.prepare_packet(c.MSG_RESPONSE_USER_EXISTS, nonce=n1)

            if username not in self.pw_dict:
                self.stage = c.AUTH_STAGE_INIT
                return PacketOrganiser.prepare_packet(c.MSG_RESPONSE_WRONG_CR, nonce=n1)

            self.username = username
            dec_dh_pub_client = int(dec_dh_pub_client)
            dh_pri_key = self.crypto_service.get_dh_pri_key()
            dh_pub_server = self.crypto_service.get_dh_pub_key(dh_pri_key)
            self.dh_key = self.crypto_service.get_dh_secret(dh_pri_key, dec_dh_pub_client)
            # compose response: public key, K{N1, salt}, sign whole message
            salt = self.pw_dict[self.username][1]  # get salt from username
            salt_pack = PacketOrganiser.prepare_packet(salt, nonce=n1, add_time=False)
            enc_salt = self.crypto_service.sym_encrypt(self.dh_key, salt_pack)
            msg = PacketOrganiser.prepare_packet([dh_pub_server, enc_salt, ""], add_time=False)
            sign = self.crypto_service.rsa_sign(msg)

            signed_msg = PacketOrganiser.prepare_packet([msg, sign, ""], add_time=False)
            self.stage = c.AUTH_STAGE_2
            return signed_msg
    def _step_1_dh_key_establish(self, sock, chl, k, ind, username):
        """
        DH contribution exchange
        :param sock:
        :param chl:
        :param k:
        :param ind:
        :return:
        """
        ans = self.ra.compute_answer(chl, k)
        dh_pri_key = self.crypto_service.get_dh_pri_key()
        dh_pub_key = self.crypto_service.get_dh_pub_key(dh_pri_key)
        msg_to_send_parts = [dh_pub_key, username, ""]
        nonce = PacketOrganiser.genRandomNumber()
        msg_to_send = PacketOrganiser.prepare_packet(msg_to_send_parts, nonce=nonce, add_time=False)
        enc_msg_to_send = self.crypto_service.rsa_encrypt(msg_to_send)
        auth_1_msg_parts = [ans, ind, enc_msg_to_send]
        auth_1_msg = PacketOrganiser.prepare_packet(auth_1_msg_parts, add_time=False)
        sock.sendto(auth_1_msg, self.server_addr)

        recv_msg = util.get_one_response(sock, self.server_addr)
        # print("Receive msg from {}, length: {}".format(self.server_addr, len(recv_msg)))
        _, msg_sign = PacketOrganiser.process_packet(recv_msg)

        if msg_sign[0] == c.MSG_RESPONSE_WRONG_CR:
            print(c.WRONG_CR_MSG)
            return
        elif msg_sign[0] == c.MSG_RESPONSE_USER_EXISTS:
            print(c.USER_ALREADY_LOGIN_MSG)
            return
        else:
            msg, sign, _ = msg_sign
            if not self.crypto_service.rsa_verify(msg, sign):  # TODO for testing
                raise Exception(c.STEP_ONE_FAIL_MSG)
            _, pub_enc_salt = PacketOrganiser.process_packet(msg)
            other_pub_key, enc_salt, _ = pub_enc_salt
            other_pub_key = int(other_pub_key)
            self.dh_key = self.crypto_service.get_dh_secret(dh_pri_key, other_pub_key)
            dec_salt_pack = self.crypto_service.sym_decrypt(self.dh_key, enc_salt)
            n1, salt_parts = PacketOrganiser.process_packet(dec_salt_pack)
            salt = salt_parts[0]

            if n1 == nonce:
                return salt
from CryptoService import CryptoService
from ClientServerAuthentication import ClientServerAuthentication
from ClientClientAuthentication import ClientClientAuthentication
import Consts as c
from UserInputHandler import UserInputHandler
from PacketOrganiser import PacketOrganiser
from ClientChattingService import ClientChattingService
import time

server_auth = None
active_users = {}  # active user list from server
addr_auths = {}  # addr : auth
user_addr_dict = {}  # username : addr
request_cache = {
}  # nonce : [request type, msg, key, addr, ts, auth for pre-auth <get TTB from server> (if any)]
packetorg = PacketOrganiser()


class ListenThread(threading.Thread):
    def __init__(self, sock, saddr):
        """
        sock: socket used for sending message to server
        saddr: server address
        """
        threading.Thread.__init__(self)
        self.sock = sock
        self.listen = True  # flag for terminate the thread
        self.server_addr = saddr

    def run(self):
        """
def get_good_nonce(dict):
    nonce = PacketOrganiser.genRandomNumber()
    while nonce in dict:
        nonce = PacketOrganiser.genRandomNumber()
    return nonce
def run_client(server_ip, server_port):
    """
    Main function to start the client.
    server_ip: IP address of the server
    server_port: port number which server uses to communicate
    """
    global server_auth, user_addr_dict, active_users
    g = 2
    p = util.load_df_param_from_file(c.DH_CONFIG_PATH)
    crypto_service = CryptoService(rsa_pub_path=c.PUB_KEY_PATH, p=p, g=g)

    server_addr = (server_ip, server_port)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    client_port = server_port + 1
    local_ip = socket.gethostbyname(socket.gethostname())
    client_addr = (local_ip, client_port)

    # try to find a available local port
    port_found = False
    while not port_found:
        try:
            sock.bind(client_addr)
            port_found = True
        except socket.error:
            client_addr = (client_addr[0], client_addr[1] + 1)
            continue

    server_auth = ClientServerAuthentication(client_addr, server_addr,
                                             crypto_service)

    try:
        server_auth.authenticate_with_server(sock)
    except socket.error:
        print Consts.FAIL_GRE_MSG
        return

    chat_service = ClientChattingService(active_users, server_auth)

    # start a background to handle user input
    t_listen = ListenThread(sock, server_addr)
    t_listen.start()

    # start a background to resend message
    t_resend = ResendThread(sock, request_cache)
    t_resend.start()

    sys.stdout.write(Consts.PROMPT)
    sys.stdout.flush()

    while True:
        try:
            # listening to the server and display the message
            recv_msg, r_addr = sock.recvfrom(20480)
            if r_addr == server_addr and recv_msg:
                dec_msg = crypto_service.sym_decrypt(server_auth.dh_key,
                                                     recv_msg)
                n, msg_ps = PacketOrganiser.process_packet(dec_msg)
                # first check if it's a client/client authentication
                # response from server
                if n in request_cache:
                    # check the type of request
                    cache = request_cache[n]
                    request_type = cache[c.CACHE_TYPE_IND]
                    if request_type == c.MSG_TYPE_LOGOUT:
                        # process logout confirmation
                        if msg_ps[0] == c.MSG_RESPONSE_OK:
                            request_cache.pop(n)
                            break
                    elif request_type == c.MSG_TYPE_START_NEW_CHAT:
                        # process the auth response from server
                        cur_auth = cache[c.CACHE_AUTH_IND]
                        assert isinstance(cur_auth, ClientClientAuthentication)
                        b_addr = cur_auth.start_authenticate(
                            sock, msg_ps, server_auth.username)
                        user_addr_dict[cur_auth.username] = b_addr
                        addr_auths[b_addr] = cur_auth
                        request_cache.pop(n)
                    elif request_type == c.MSG_TYPE_LIST:
                        # process the user list form server
                        chat_service.process_message(msg_ps)
                        request_cache.pop(n)
                    elif request_type == c.ERR_CLIENT_DOWN:
                        print(c.ERR_CLIENT_DOWN)
                        request_cache.pop(n)
            elif r_addr in addr_auths:  #Reply or chat request from client
                cur_auth = addr_auths[r_addr]
                dec_msg = crypto_service.sym_decrypt(cur_auth.dh_key, recv_msg)

                n, dec_msg_parts = PacketOrganiser.process_packet(dec_msg)
                type = dec_msg_parts[0]

                if cur_auth.auth_success:
                    if type == c.MSG_RESPONSE_OK:
                        if n in request_cache:
                            cache = request_cache[n]
                            request_type = cache[c.CACHE_TYPE_IND]
                            if request_type == c.MSG_TYPE_MSG:
                                request_cache.pop(n)
                                continue

                    elif type == c.MSG_TYPE_MSG:
                        # display user message
                        msg_hmac = dec_msg_parts[1]
                        # check the HMAC
                        msg, sign = PacketOrganiser.divide_signature(msg_hmac)
                        if CryptoService.verify_hmac_sign(
                                cur_auth.dh_key, msg, sign):
                            util.display_user_message(msg, cur_auth.username)
                            # send message confirmation back
                            util.send_confirmation(sock, crypto_service,
                                                   cur_auth.dh_key, n, r_addr)
                else:
                    # deal with peer auth success msg
                    if type == c.MSG_RESPONSE_OK:
                        if n in request_cache:
                            cache = request_cache[n]
                            request_type = cache[c.CACHE_TYPE_IND]
                            if request_type == c.MSG_TYPE_PUB_KEY:
                                # verify nonce
                                if n != cur_auth.last_nonce:
                                    continue
                                else:
                                    cur_auth.auth_success = True
                                    request_cache.pop(n)
                                    # check the HMAC
                                    msg_hmac = dec_msg_parts[1]
                                    msg, sign = PacketOrganiser.divide_signature(
                                        msg_hmac)
                                    if CryptoService.verify_hmac_sign(
                                            cur_auth.dh_key, msg, sign):
                                        # display user message
                                        util.display_user_message(
                                            msg, cur_auth.username)
                                        # send message confirmation back
                                        util.send_confirmation(
                                            sock, crypto_service,
                                            cur_auth.dh_key, n, r_addr)

                    elif type == c.MSG_TYPE_PUB_KEY:
                        # finish peer authentication on Alice side
                        b_pub_key = int(dec_msg_parts[1])
                        cur_auth.dh_key = crypto_service.get_dh_secret(
                            cur_auth.pri_key, b_pub_key)
                        cur_auth.auth_success = True
                        cur_auth.last_nonce = n
                        # send confirmation and first message to Bob
                        hmac = CryptoService.generate_hmac_sign(
                            cur_auth.dh_key, cur_auth.first_msg)
                        first_msg_hmac = cur_auth.first_msg + hmac
                        conf_msg_parts = [
                            c.MSG_RESPONSE_OK, first_msg_hmac, ""
                        ]
                        conf_msg = PacketOrganiser.prepare_packet(
                            conf_msg_parts, n)
                        enc_conf_msg = crypto_service.sym_encrypt(
                            cur_auth.dh_key, conf_msg)
                        # add to request cache
                        # a hack here (TYPE_MSG instead of RESPONSE_OK) to make the confirmation work
                        util.add_to_request_cache(request_cache, n,
                                                  c.MSG_TYPE_MSG,
                                                  cur_auth.dh_key, conf_msg,
                                                  r_addr)
                        sock.sendto(enc_conf_msg, r_addr)
            else:  # the r_addr not in user_addr_dict, this can be a TTB
                # handle TTB from Alice
                _, msg_ps = PacketOrganiser.process_packet(recv_msg)
                signed_ttb, enc_inside_msg, _ = msg_ps
                ttb = signed_ttb[:-c.RSA_SIGN_LENGTH]
                sign = signed_ttb[-c.RSA_SIGN_LENGTH:]
                if not crypto_service.rsa_verify(ttb, sign):
                    raise Exception(c.WARNING_TTB_INVALID)
                dec_ttb = crypto_service.sym_decrypt(server_auth.dh_key, ttb)
                _, ttb_parts = PacketOrganiser.process_packet(
                    dec_ttb)  # a_username, a_addr, k_ab
                a_username_ttb, a_addr, k_ab = ttb_parts
                a_addr = util.str_to_addr(a_addr)
                # decrypt inside message with k_ab
                dec_inside_msg = crypto_service.sym_decrypt(
                    k_ab, enc_inside_msg)
                _, inside_msg_parts = PacketOrganiser.process_packet(
                    dec_inside_msg)
                a_username, a_pub_key, _ = inside_msg_parts
                # print("username_ttb: {}, a_username: {}".format(a_username_ttb, a_username))
                if a_username_ttb != a_username:
                    raise Exception(c.WARNING_TTB_USERNAME_INVALID)
                new_auth = ClientClientAuthentication(a_username,
                                                      crypto_service)
                pri_key = crypto_service.get_dh_pri_key()
                pub_key = crypto_service.get_dh_pub_key(pri_key)
                new_auth.dh_key = crypto_service.get_dh_secret(
                    pri_key, int(a_pub_key))
                nonce = util.get_good_nonce(request_cache)
                new_auth.last_nonce = nonce
                # send pub key to Alice
                msg_parts = [c.MSG_TYPE_PUB_KEY, pub_key, ""]
                plain_msg = PacketOrganiser.prepare_packet(msg_parts, nonce)
                enc_msg = crypto_service.sym_encrypt(k_ab, plain_msg)
                sock.sendto(enc_msg, a_addr)
                # add new auth to dict
                addr_auths[a_addr] = new_auth
                user_addr_dict[a_username] = a_addr
                util.add_to_request_cache(request_cache, nonce,
                                          c.MSG_TYPE_PUB_KEY, k_ab, plain_msg,
                                          a_addr)  # add to request cache
        except socket.error:
            # sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            # sock.bind(client_addr)
            continue
        except KeyboardInterrupt:
            # when seeing ctrl-c terminate the client
            t_listen.stop()
            t_listen.join()
            t_resend.stop()
            t_resend.join()
            print c.BYE
            server_auth.logout(sock)
            sock.close()
            return
        except:
            pass
    t_listen.stop()
    t_listen.join()
    t_resend.stop()
    t_resend.join()
    print c.BYE
    server_auth.logout(sock)
    sock.close()
Esempio n. 37
0
 def logout(self, sock):
     msg = PacketOrganiser.prepare_packet(c.MSG_TYPE_LOGOUT)
     enc_msg = self.crypto_service.sym_encrypt(self.dh_key, msg)
     sock.sendto(enc_msg, self.server_addr)
 def logout(self, sock):
     msg = PacketOrganiser.prepare_packet(c.MSG_TYPE_LOGOUT)
     enc_msg = self.crypto_service.sym_encrypt(self.dh_key, msg)
     sock.sendto(enc_msg, self.server_addr)
def run_client(server_ip, server_port):
    """
    Main function to start the client.
    server_ip: IP address of the server
    server_port: port number which server uses to communicate
    """
    global server_auth, user_addr_dict, active_users
    g = 2
    p = util.load_df_param_from_file(c.DH_CONFIG_PATH)
    crypto_service = CryptoService(rsa_pub_path=c.PUB_KEY_PATH, p=p, g=g)

    server_addr = (server_ip, server_port)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    client_port = server_port + 1
    local_ip = socket.gethostbyname(socket.gethostname())
    client_addr = (local_ip, client_port)

    # try to find a available local port
    port_found = False
    while not port_found:
        try:
            sock.bind(client_addr)
            port_found = True
        except socket.error:
            client_addr = (client_addr[0], client_addr[1] + 1)
            continue

    server_auth = ClientServerAuthentication(client_addr, server_addr, crypto_service)

    try:
        server_auth.authenticate_with_server(sock)
    except socket.error:
        print Consts.FAIL_GRE_MSG
        return

    chat_service = ClientChattingService(active_users, server_auth)

    # start a background to handle user input
    t_listen = ListenThread(sock, server_addr)
    t_listen.start()

    # start a background to resend message
    t_resend = ResendThread(sock, request_cache)
    t_resend.start()

    sys.stdout.write(Consts.PROMPT)
    sys.stdout.flush()

    while True:
        try:
            # listening to the server and display the message
            recv_msg, r_addr = sock.recvfrom(20480)
            if r_addr == server_addr and recv_msg:
                dec_msg = crypto_service.sym_decrypt(server_auth.dh_key, recv_msg)
                n, msg_ps = PacketOrganiser.process_packet(dec_msg)
                # first check if it's a client/client authentication
                # response from server
                if n in request_cache:
                    # check the type of request
                    cache = request_cache[n]
                    request_type = cache[c.CACHE_TYPE_IND]
                    if request_type == c.MSG_TYPE_LOGOUT:
                        # process logout confirmation
                        if msg_ps[0] == c.MSG_RESPONSE_OK:
                            request_cache.pop(n)
                            break
                    elif request_type == c.MSG_TYPE_START_NEW_CHAT:
                        # process the auth response from server
                        cur_auth = cache[c.CACHE_AUTH_IND]
                        assert isinstance(cur_auth, ClientClientAuthentication)
                        b_addr = cur_auth.start_authenticate(sock, msg_ps, server_auth.username)
                        user_addr_dict[cur_auth.username] = b_addr
                        addr_auths[b_addr] = cur_auth
                        request_cache.pop(n)
                    elif request_type == c.MSG_TYPE_LIST:
                        # process the user list form server
                        chat_service.process_message(msg_ps)
                        request_cache.pop(n)
                    elif request_type == c.ERR_CLIENT_DOWN:
                        print(c.ERR_CLIENT_DOWN)
                        request_cache.pop(n)
            elif r_addr in addr_auths:   #Reply or chat request from client
                cur_auth = addr_auths[r_addr]
                dec_msg = crypto_service.sym_decrypt(cur_auth.dh_key, recv_msg)

                n, dec_msg_parts = PacketOrganiser.process_packet(dec_msg)
                type = dec_msg_parts[0]

                if cur_auth.auth_success:
                    if type == c.MSG_RESPONSE_OK:
                        if n in request_cache:
                            cache = request_cache[n]
                            request_type = cache[c.CACHE_TYPE_IND]
                            if request_type == c.MSG_TYPE_MSG:
                                request_cache.pop(n)
                                continue

                    elif type == c.MSG_TYPE_MSG:
                        # display user message
                        msg_hmac = dec_msg_parts[1]
                        # check the HMAC
                        msg, sign = PacketOrganiser.divide_signature(msg_hmac)
                        if CryptoService.verify_hmac_sign(cur_auth.dh_key, msg, sign):
                            util.display_user_message(msg, cur_auth.username)
                            # send message confirmation back
                            util.send_confirmation(sock, crypto_service, cur_auth.dh_key, n, r_addr)
                else:
                    # deal with peer auth success msg
                    if type == c.MSG_RESPONSE_OK:
                        if n in request_cache:
                            cache = request_cache[n]
                            request_type = cache[c.CACHE_TYPE_IND]
                            if request_type == c.MSG_TYPE_PUB_KEY:
                                # verify nonce
                                if n != cur_auth.last_nonce:
                                    continue
                                else:
                                    cur_auth.auth_success = True
                                    request_cache.pop(n)
                                    # check the HMAC
                                    msg_hmac = dec_msg_parts[1]
                                    msg, sign = PacketOrganiser.divide_signature(msg_hmac)
                                    if CryptoService.verify_hmac_sign(cur_auth.dh_key, msg, sign):
                                        # display user message
                                        util.display_user_message(msg, cur_auth.username)
                                        # send message confirmation back
                                        util.send_confirmation(sock, crypto_service, cur_auth.dh_key, n, r_addr)

                    elif type == c.MSG_TYPE_PUB_KEY:
                        # finish peer authentication on Alice side
                        b_pub_key = int(dec_msg_parts[1])
                        cur_auth.dh_key = crypto_service.get_dh_secret(cur_auth.pri_key, b_pub_key)
                        cur_auth.auth_success = True
                        cur_auth.last_nonce = n
                        # send confirmation and first message to Bob
                        hmac = CryptoService.generate_hmac_sign(cur_auth.dh_key, cur_auth.first_msg)
                        first_msg_hmac = cur_auth.first_msg + hmac
                        conf_msg_parts = [c.MSG_RESPONSE_OK, first_msg_hmac, ""]
                        conf_msg = PacketOrganiser.prepare_packet(conf_msg_parts, n)
                        enc_conf_msg = crypto_service.sym_encrypt(cur_auth.dh_key, conf_msg)
                        # add to request cache
                        # a hack here (TYPE_MSG instead of RESPONSE_OK) to make the confirmation work
                        util.add_to_request_cache(request_cache, n, c.MSG_TYPE_MSG, cur_auth.dh_key, conf_msg, r_addr)
                        sock.sendto(enc_conf_msg, r_addr)
            else: # the r_addr not in user_addr_dict, this can be a TTB
                # handle TTB from Alice
                _, msg_ps = PacketOrganiser.process_packet(recv_msg)
                signed_ttb, enc_inside_msg, _ = msg_ps
                ttb = signed_ttb[:-c.RSA_SIGN_LENGTH]
                sign = signed_ttb[-c.RSA_SIGN_LENGTH:]
                if not crypto_service.rsa_verify(ttb, sign):
                    raise Exception(c.WARNING_TTB_INVALID)
                dec_ttb = crypto_service.sym_decrypt(server_auth.dh_key, ttb)
                _, ttb_parts = PacketOrganiser.process_packet(dec_ttb)  # a_username, a_addr, k_ab
                a_username_ttb, a_addr, k_ab = ttb_parts
                a_addr = util.str_to_addr(a_addr)
                # decrypt inside message with k_ab
                dec_inside_msg = crypto_service.sym_decrypt(k_ab, enc_inside_msg)
                _, inside_msg_parts = PacketOrganiser.process_packet(dec_inside_msg)
                a_username, a_pub_key, _ = inside_msg_parts
                # print("username_ttb: {}, a_username: {}".format(a_username_ttb, a_username))
                if a_username_ttb != a_username:
                    raise Exception(c.WARNING_TTB_USERNAME_INVALID)
                new_auth = ClientClientAuthentication(a_username, crypto_service)
                pri_key = crypto_service.get_dh_pri_key()
                pub_key = crypto_service.get_dh_pub_key(pri_key)
                new_auth.dh_key = crypto_service.get_dh_secret(pri_key, int(a_pub_key))
                nonce = util.get_good_nonce(request_cache)
                new_auth.last_nonce = nonce
                # send pub key to Alice
                msg_parts = [c.MSG_TYPE_PUB_KEY, pub_key, ""]
                plain_msg = PacketOrganiser.prepare_packet(msg_parts, nonce)
                enc_msg = crypto_service.sym_encrypt(k_ab, plain_msg)
                sock.sendto(enc_msg, a_addr)
                # add new auth to dict
                addr_auths[a_addr] = new_auth
                user_addr_dict[a_username] = a_addr
                util.add_to_request_cache(request_cache, nonce, c.MSG_TYPE_PUB_KEY, k_ab, plain_msg, a_addr) # add to request cache
        except socket.error:
            # sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            # sock.bind(client_addr)
            continue
        except KeyboardInterrupt:
            # when seeing ctrl-c terminate the client
            t_listen.stop()
            t_listen.join()
            t_resend.stop()
            t_resend.join()
            print c.BYE
            server_auth.logout(sock)
            sock.close()
            return
        except:
            pass
    t_listen.stop()
    t_listen.join()
    t_resend.stop()
    t_resend.join()
    print c.BYE
    server_auth.logout(sock)
    sock.close()
def get_good_nonce(dict):
    nonce = PacketOrganiser.genRandomNumber()
    while nonce in dict:
        nonce = PacketOrganiser.genRandomNumber()
    return nonce