Example #1
0
    def __init__(self, database):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind((SERVER_IP_ADDR, SERVER_TCP_PORT))  # bind to port
        self.sock.listen(1)  # listen with one pending connection

        # each connection maps to a hashmap, which keySet are {expect, dh_shared_key, addr, challenge, name}
        self.client_conn = {}
        # maps name to his/her ip address: name -> (ip, port)
        self.online_client = {}
        self.inputs = [self.sock]
        self.secret = os.urandom(16)

        # Loads user credential database into memory
        self.client_credentials = {}
        with open(database, 'rb') as datafile:
            for line in datafile:
                parts = line.split('\t')
                name = parts[0]
                self.client_credentials[name] = {}
                w1 = base64.b64decode(parts[1])
                self.client_credentials[name]['w1_salt'] = w1[:16]
                self.client_credentials[name]['w1'] = w1[16:]
                self.client_credentials[name][
                    'pub'] = utils.deserialize_public_key(
                        base64.b64decode(parts[3]))
                self.client_credentials[name]['pri'] = base64.b64decode(
                    parts[2])
Example #2
0
    def __handle_server_dhpub(self, rqst, rply):
        decrypted_key_bytes = b64decode_aes_cgm_decrypt(
            rply.public_key, self.w1)
        server_dh_public = utils.deserialize_public_key(decrypted_key_bytes)
        # compute shared key
        self.dh_shared = utils.generate_dh_key(self.dh_private,
                                               server_dh_public)

        # So we can compute y = W'{rsa private key} now
        y = b64decode_aes_cgm_decrypt(rply.private_key, self.dh_shared)

        # decrypt with W' and extract rsa private key
        self.w2_salt, iv1, tag, cipher_private = y[:16], y[16:32], y[32:48], y[
            48:]
        self.w2 = utils.password_to_w(self.w2_salt, self.password,
                                      utils.w2_iteration, utils.w2_length)
        private_key_bytes = utils.aes_cgm_decrypt(cipher_private, self.w2, iv1,
                                                  tag)
        self.private_key = utils.deserialize_private_key(private_key_bytes)

        rqst.type = ClientToServer.USER_SIGN
        digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
        digest.update(self.dh_shared)
        digest.update(base64.b64decode(rply.challenge))
        hash_value = digest.finalize()
        # rqst.hash = base64.b64encode(hash_value)
        sign = self.private_key.sign(
            hash_value,
            padding.PSS(mgf=padding.MGF1(hashes.SHA256()),
                        salt_length=padding.PSS.MAX_LENGTH), hashes.SHA256())
        rqst.sign = base64.b64encode(sign)
        rqst.ip = Client_IP_ADDR
        rqst.port = str(self.listen_port)
        self.server_sock.send(rqst.SerializeToString())
        logger.debug('__handle_server_dhpub: Processed SERVER_PUBKEY rqst')
Example #3
0
    def __handle_user_dh_pubkey(self, rqst, rply, conn):
        # server are expecting user's public key form next msg, all other kind of msg will be ignored or warned
        self.client_conn[conn]['expect'] = ClientToServer.USER_SIGN
        digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
        digest.update(self.client_conn[conn]['addr'][0].encode())
        digest.update(self.secret)
        msg_digest = base64.b64encode(digest.finalize())
        # Checking for Dos attack
        if msg_digest != rqst.challenge:
            # log the DoS attack msg, and forget this connection
            logger.error(
                '__handle_user_dh_pubkey: Wrong hash, possible DoS: ' +
                self.client_conn[conn]['name'])
            # forget the connection
            self.inputs.remove(conn)
            self.client_conn.pop(conn, None)
            conn.close()
        else:
            try:
                # self.client_conn[conn]['client_pub'] = rqst.public_key
                # generate its own DH key
                server_dh_private_key = ec.generate_private_key(
                    ec.SECP384R1(), default_backend())
                # client's public DH key and shared DH key
                client_dh_public = utils.deserialize_public_key(
                    base64.b64decode(rqst.public_key))
                # using self.client_conn[conn]['dh_shared_key'] as shared key for further encrypting
                self.client_conn[conn][
                    'dh_shared_key'] = utils.generate_dh_key(
                        server_dh_private_key, client_dh_public)
                self.client_conn[conn]['challenge'] = os.urandom(16)

                name = self.client_conn[conn]['name']
                w1 = self.client_credentials[name]['w1']
                server_dh_public_serialized = server_dh_private_key \
                    .public_key() \
                    .public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo)

                rply.type = ServerToClient.SERVER_PUBKEY
                rply.public_key = b64encode_aes_cgm_encrypt(
                    server_dh_public_serialized, w1)
                rply.challenge = base64.b64encode(
                    self.client_conn[conn]['challenge'])
                rply.private_key = b64encode_aes_cgm_encrypt(
                    self.client_credentials[name]['pri'],
                    self.client_conn[conn]['dh_shared_key'])
                conn.send(rply.SerializeToString())
                logger.debug(
                    '__handle_user_dh_pubkey: Successful send dh_pub key: ' +
                    self.client_conn[conn]['name'])
            except Exception as e:
                logger.error(
                    "__handle_user_dh_pubkey: Fail to finish authentication" +
                    str(e))
                rply.type = ServerToClient.ERROR
                rply.info = "Fail to finish authentication"
                conn.send(rply.SerializeToString())
Example #4
0
 def __handle_recver_pub(self, rqst, s):
     rcver_dh_pub_bytes = base64.b64decode(rqst.public_key)
     recver_pub = utils.deserialize_public_key(rcver_dh_pub_bytes)
     # generate our own DH key
     self.conn_info[s]['shared_dh'] = utils.generate_dh_key(
         self.conn_info[s]['sender_dh_private'], recver_pub)
     self.conn_info[s]['expect'] = ClientToClient.RECVER_IDENTITY
     # cached sender_dh_pub_key_bytes
     # since we will have to verify signature of public key in the future protocol msg
     self.conn_info[s]['rcver_dh_pub_bytes'] = rcver_dh_pub_bytes
     # According to protocol, send back (g^ab mod p){"Alice", [g^a mod p]sign}
     self.__send_identity(self.conn_info[s]['sender_dh_private'],
                          ClientToClient.SENDER_IDENTITY, s)
     logger.debug('__handle_recver_pub: Send identity as sender to ' +
                  self.conn_info[s]['name'])
Example #5
0
 def __handle_sender_pub(self, rqst, s):
     sender_dh_pub_key_bytes = base64.b64decode(rqst.public_key)
     sender_dh_pub_key = utils.deserialize_public_key(
         sender_dh_pub_key_bytes)
     # generate our own DH key
     rcver_dh_private_key = ec.generate_private_key(ec.SECP384R1(),
                                                    default_backend())
     # compute shared key
     shared_key = utils.generate_dh_key(rcver_dh_private_key,
                                        sender_dh_pub_key)
     # cached sender_dh_pub_key_bytes
     # since we will have to verify signature of public key in the future protocol msg
     self.conn_info[s] = {
         'shared_dh': shared_key,
         'expect': ClientToClient.SENDER_IDENTITY,
         'rcver_dh_private': rcver_dh_private_key,
         'sender_dh_pub_bytes': sender_dh_pub_key_bytes
     }
     # send DH public key back
     self.__send_dh_pub(rcver_dh_private_key, ClientToClient.RECVER_PUB, s)
     logger.debug('__handle_sender_pub: Send dh pub as receiver ' +
                  self.name)
Example #6
0
    def __handle_server_sock(self):
        while self.login:
            try:
                encrypted_data = self.server_sock.recv(BUFFER_SIZE)
            except:
                encrypted_data = ''
            if len(encrypted_data) == 0:
                # len(encrypted_data) == 0 means server is closing socket, so client can terminate program now
                self.server_sock.close()
                self.login = False
                logger.error('__handle_server_sock: Server is shutting down')
                return
            data = b64decode_aes_cgm_decrypt(encrypted_data, self.dh_shared)
            rply = ServerToClient()
            rply.ParseFromString(data)
            if abs(rply.time - time.time()) > TIME_TOLERANCE:
                # ignore the messages that are outdated
                logger.warn('__handle_server_sock: Message is too outdated')
                continue
            # server is ready to logout the user, prepare to close the socket
            if rply.type == ServerToClient.LOGOUT and self.server_expect[
                    'Logout']:
                self.login = False
                self.server_sock.close()
                return
            # server replies with all login users
            if rply.type == ServerToClient.REPLY_LIST and self.server_expect[
                    'List']:
                self.server_expect['List'] = False
                online_users = []
                for online_user in rply.name_list:
                    online_users.append(online_user)
                print ', '.join(online_users)
            # server replies with query
            elif rply.type == ServerToClient.REPLY_QUERY and rply.name in self.server_expect[
                    'Query']:
                self.server_expect['Query'].remove(rply.name)
                # update meta data, in case of peer re-login or changing public key
                self.peer_info[
                    rply.name]['pub'] = utils.deserialize_public_key(
                        base64.b64decode(rply.public_key))
                self.peer_info[rply.name]['ip'] = rply.ip
                self.peer_info[rply.name]['port'] = rply.port

                # if we are the sender, then we haven't established connection with this peer
                if 'conn' not in self.peer_info[rply.name]:
                    logger.debug(
                        '__handle_server_sock: Receive pub key as sender to' +
                        rply.name)
                    self.__initiate_auth(rply.name)
                else:
                    # if we are receiver, then we already establish the connection
                    # we are in the step 3 of authentication protocol. After retrieving peer's public key
                    # we can verify the signature, and sends back our own sign: g^ab mod p{"Bob", [g^b mod p]sign}
                    conn = self.peer_info[rply.name]['conn']
                    self.peer_info[rply.name]['pub'].verify(
                        base64.b64decode(self.conn_info[conn]['sign']),
                        self.conn_info[conn]['sender_dh_pub_bytes'],
                        padding.PSS(mgf=padding.MGF1(hashes.SHA256()),
                                    salt_length=padding.PSS.MAX_LENGTH),
                        hashes.SHA256())
                    self.__send_identity(
                        self.conn_info[conn]['rcver_dh_private'],
                        ClientToClient.RECVER_IDENTITY, conn)
                    logger.debug(
                        '__handle_server_sock: Receive pub key as receiver to'
                        + rply.name)
                    logger.debug('__handle_server_sock: and send identity')
            if rply.type == ServerToClient.ERROR:
                print 'Error information: from server: ' + rply.info