Ejemplo n.º 1
0
 def load(self):
     path = self.pathEdit.text()
     try:
         e = EncryptionHandler()
         f = open(path, 'rb')
         data = f.read()
         f.close()
         password = self.passEdit.text().encode()
         priv, salt = split(data, 2400)
         iv = sha256(password + salt)[:16]
         e.generateAESObject(password, salt, iv, iterations=10000)
         priv = e.AESDecrypt(priv)
         self.dialog.rsa_key = priv
         msg = 'Successfully loaded keyfile!'
         self.dialog.addChatHistory(msg)
         self.logger.log(msg)
     except VerificationError as err:
         err_msg = 'Error decrypting the file: ' + str(err) + ' (Wrong password?)'
         self.logger.log(err_msg, True)
         self.dialog.appendNormalMessage(err_msg)
         self.dialog.rsa_key = None
     except IOError as err:
         err_msg = "IO-Error: Couldn't open file."
         self.logger.log(err_msg, True)
         self.dialog.appendNormalMessage(err_msg)
     except BaseException as err:
         self.logger.log(str(err), True)
         self.dialog.appendNormalMessage(str(err))
     finally:
         self.close()
Ejemplo n.º 2
0
 def generate(self):
     try:
         path = self.pathEdit.text()
         password = self.passEdit.text().encode()
         e = EncryptionHandler(id(password))
         salt = e.random(256)
         e.generateRSAKeys()
         iv = sha256(password + salt)[:16]
         e.generateAESObject(password, salt, iv, iterations=10000)
         priv = e.exportPrivateKey()
         self.dialog.rsa_key = priv
         priv = e.AESEncrypt(priv, 2400)
         if os.path.exists(path):
             os.remove(path)
         f = open(path, 'wb')
         f.write(priv + salt)
         f.close()
         msg = 'Successfully generated new keyfile!'
         self.dialog.addChatHistory(msg)
         self.logger.log(msg)
     except IOError as err:
         err_msg = "IO-Error: Couldn't save file."
         self.logger.log(err_msg, True)
         self.dialog.appendNormalMessage(err_msg)
     except BaseException as err:
         self.logger.log(str(err), True)
         self.dialog.appendNormalMessage(str(err))
     finally:
         self.close()
Ejemplo n.º 3
0
    def __init__(self):
        self.logger = Logger('Server', onlyErrors=False)
        self.logger.log('Starting CryptoChatServer(preAlpha).')
        # Input
        #self.server_name = input('Server-Name: ')
        #self.server_port = int(input('Server-Port: '))
        #self.server_password = input('Password: '******'CryptoChatServer(preAlpha)'
        self.server_port = 50000
        self.server_password = '******'
        #ek = input('Encryptionkey: ').encode()
        ek = 'Beispielschlüssel sind eine tolle Sache!!!'.encode()

        # Data for managing clients
        #self.encryption_Handler = EncryptionHandler(ek, self.logger, 'MainEH') Logging EncryptionHandler
        self.encryption_Handler = EncryptionHandler(ek)
        self.clients = {}
        self.master_token = None
        self.logger.log('Generating token and encryption keys.')
        self.token = self.encryption_Handler.random(16)
        while self.token == BROADCAST_TOKEN:
            self.token = self.encryption_Handler.random(16)
        self.socket = None
        self.handler = None
        self.encryption_Handler.generateAESObject(ek)
        self.encryption_Handler.generateRSAKeys()
        set_zero(ek)
        
        # Create TCP-Socket
        self.logger.log('Setting up TCP-Socket.')
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # For double usage of same IP after restart
        self.socket.settimeout(2)
        self.logger.log('Binding to port {}.'.format(self.server_port))
        self.socket.bind(('', self.server_port))
        self.socket.listen(1)
        self.logger.log('Starting Handler.')
        self.handler = ClientHandler(self)
        self.handler.start()
        self.logger.log('Handler started.')
        self.ping_checker = PingThread(self)
        self.ping_checker.start()
        self.logger.log('PingThread started.')

        self.logger.log('Server-Init done!')
        self.logger.log('Server-Name: ' + self.server_name)
        self.logger.log('Server-Port: ' + str(self.server_port))
        self.logger.log('Server-Token: ' + toHex(self.token))
Ejemplo n.º 4
0
def connect(name, ip, password, port, encryptionsalt, dialog):
	logger = dialog.logger
	logger.log('Connecting to {}:{}'.format(ip, port))
	def signed_send(msg, ehandler, server, length=512):
		signature = ehandler.sign(msg)
		e_msg = ehandler.AESEncrypt(msg, length)
		server.sendall(e_msg + signature)

	def verified_recv(ehandler, server, length=512):
		length += 512
		msg = server.recv(length)
		signature = msg[length-512:]
		msg = msg[:length-512]
		msg = ehandler.AESDecrypt(msg)
		if not ehandler.verify(msg, signature):
			raise VerificationError('Wrong signature from server!')
		return msg
	#
	# This will be the EncryptionHandler for the connection to
	# the server. It will later recieve the global AES-key.
	#
	salt = getSaltOutOfCursorPos()
	#e = EncryptionHandler(encryptionsalt.encode() + salt, logger, 'ServerEH')
	e = EncryptionHandler(encryptionsalt.encode() + salt)
	#
	# This key and initialization vector will be used for
	# this login and later be replaced with the global AES-key.
	#
	dialog.addChatHistory('Generating keys...')
	key, iv = e.generateAESObject((name + password).encode() + salt + encryptionsalt.encode() + toBytes(id(e)), iterations=15000)
	if dialog.rsa_key is None:
		e.generateRSAKeys()
	else:
		e.importPrivateKey(dialog.rsa_key)
	#
	# Creating the socket for communication over TCP.
	#
	s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	try:
		#
		# Connecting to the server.
		#
		dialog.addChatHistory('Connecting to {}/{}...'.format(ip, port))
		s.connect((ip, int(port)))
		#
		# Recieving the public-key and a salt for hashing the password.
		#
		dialog.addChatHistory('Getting Public-Key...')
		data = s.recv(678)
		salt = data[:128]
		e.importPublicKey(data[128:])
		dialog.addChatHistory('Sending Password...')
		pass_hash = pbkdf2(64, password.encode(), salt)
		data = e.RSAEncrypt(pass_hash + key + iv)
		s.sendall(data + e.exportPublicKey())
		#
		# The servers response is a single byte.
		#
		dialog.addChatHistory('Waiting for response...')
		connected = s.recv(1)
		if connected == bytes([0]):
			#
			# The server rejected us.
			#
			dialog.addChatHistory('Wrong Password! Could not connect to server.')
			return False
		elif connected == bytes([1]):
			#
			# We entered the right password and can move on.
			#
			dialog.addChatHistory('Password is accepted!')
		else:
			#
			# The server gave us the wrong response. Login is aborted.
			#
			dialog.addChatHistory('Wrong response from server! Aborted login!')
			return False
		#
		# The names are exchanged.
		#
		signed_send(name.encode(), e, s)
		dialog.addChatHistory('Getting Servername...')
		server_name = verified_recv(e, s)
		dialog.appendNormalMessage('Connected to %s!' % (server_name.decode()))
		#
		# Sending our message for the server.
		#
		signed_send(b'CryptoChat [InDev]', e, s)
		#
		# We were accepted and recieved the global AES-key. We now have
		# a complete EncryptionHandler with public-key and AES-key, aswell
		# as a TCP-connection with the server.
		#
		encryptionkey = verified_recv(e, s)
		#
		# We recieve the session-id used for identifying us.
		# We also get the servers id.
		#
		session_ids = verified_recv(e, s)
		my_session_id = session_ids[:TOKEN_SIZE]
		server_session_id = session_ids[TOKEN_SIZE:]
		e.setAESObject(encryptionkey[:32], encryptionkey[32:])
		#
		# Signals for the Qt-Gui. They can only be set once we have 
		# a running serverListener.
		#
		dialog.listener = ServerListener(s, dialog)
		dialog.listener.server_encryption_Handler = e
		#dialog.listener.user_encryption_Handler = EncryptionHandler(my_session_id + salt, logger, 'ClientEH')
		dialog.listener.user_encryption_Handler = EncryptionHandler(my_session_id + salt)
		dialog.listener.user_encryption_Handler.__priv__ = e.__priv__
		dialog.listener.name = name
		dialog.listener.server_name = server_name.decode()
		dialog.listener.session_id = my_session_id
		dialog.listener.server_id = server_session_id
		dialog.connect(dialog.listener, QtCore.SIGNAL('update'), dialog.addChatHistory)
		dialog.connect(dialog.listener, QtCore.SIGNAL('updateUsers'), dialog.updateUserList)
		dialog.connect(dialog.listener, QtCore.SIGNAL('appendServerMessage'), dialog.appendServerMessage)
		dialog.connect(dialog.listener, QtCore.SIGNAL('appendNormalMessage'), dialog.appendNormalMessage)
		success = True
	except ConnectionRefusedError as err:
		err_msg = 'Could not connect to server: Connection was refused.'
		dialog.appendNormalMessage(err_msg)
		dialog.appendNormalMessage('This could mean that the server is offline.')
		logger.log(err_msg, True)
		success = False
	except socket.error as err:
		err_msg = 'Could not connect to server: ' + str(err)
		dialog.appendNormalMessage(err_msg)
		logger.log(err_msg, True)
		success = False
	except VerificationError as err:
		err_msg = 'Error verifying: ' + str(err)
		dialog.appendNormalMessage(err_msg)
		logger.log(err_msg, True)
		success = False
	return success
Ejemplo n.º 5
0
class Server():
    '''Server handling all information about clients'''
    def __init__(self):
        self.logger = Logger('Server', onlyErrors=False)
        self.logger.log('Starting CryptoChatServer(preAlpha).')
        # Input
        #self.server_name = input('Server-Name: ')
        #self.server_port = int(input('Server-Port: '))
        #self.server_password = input('Password: '******'CryptoChatServer(preAlpha)'
        self.server_port = 50000
        self.server_password = '******'
        #ek = input('Encryptionkey: ').encode()
        ek = 'Beispielschlüssel sind eine tolle Sache!!!'.encode()

        # Data for managing clients
        #self.encryption_Handler = EncryptionHandler(ek, self.logger, 'MainEH') Logging EncryptionHandler
        self.encryption_Handler = EncryptionHandler(ek)
        self.clients = {}
        self.master_token = None
        self.logger.log('Generating token and encryption keys.')
        self.token = self.encryption_Handler.random(16)
        while self.token == BROADCAST_TOKEN:
            self.token = self.encryption_Handler.random(16)
        self.socket = None
        self.handler = None
        self.encryption_Handler.generateAESObject(ek)
        self.encryption_Handler.generateRSAKeys()
        set_zero(ek)
        
        # Create TCP-Socket
        self.logger.log('Setting up TCP-Socket.')
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # For double usage of same IP after restart
        self.socket.settimeout(2)
        self.logger.log('Binding to port {}.'.format(self.server_port))
        self.socket.bind(('', self.server_port))
        self.socket.listen(1)
        self.logger.log('Starting Handler.')
        self.handler = ClientHandler(self)
        self.handler.start()
        self.logger.log('Handler started.')
        self.ping_checker = PingThread(self)
        self.ping_checker.start()
        self.logger.log('PingThread started.')

        self.logger.log('Server-Init done!')
        self.logger.log('Server-Name: ' + self.server_name)
        self.logger.log('Server-Port: ' + str(self.server_port))
        self.logger.log('Server-Token: ' + toHex(self.token))

    def getTokenList(self):
        '''Returns a list with all tokens'''
        return list(self.clients.keys())

    def getNameList(self):
        '''Returns a list with all names'''
        name_list = []
        for token in self.clients:
            name_list.append( self.clients[token].name )
        return name_list

    def send(self, msg, token=BROADCAST_TOKEN):
        '''Send a message to a certain client or all clients'''
        msg = toBytes(msg)
        header = self.encryption_Handler.AESEncrypt(self.token + token + SERVER_OPERATION, 128)
        data =  self.encryption_Handler.AESEncrypt(msg, DATA_SIZE-128)
        msg = header + data
        write = select.select([self.socket] + self.handler.clients, self.handler.clients, [])[1]
        try:
            if token == BROADCAST_TOKEN:
                for sock in write:
                    sock.sendall(msg)
            else:
                sock = self.clients[token].con
                sock.sendall(msg)
        # Connectionerrors will be ignored in this method, because they can be
        # handled more properly by the handler.
        except BrokenPipeError as err:
            self.logger.log('Broken Pipe while sending. Ignoring the error.', True)
        except ConnectionResetError as err:
            self.logger.log('Connection has been resetwhile sending. Ignoring the error.', True)
        except BaseException as err:
            self.logger.log('Unknown Error while sending: ' + str(err), True)
    
    def sendClientList(self):
        '''Send the client list to all users'''
        self.logger.log('Sending client list.')
        for token in self.clients:
            self.sendClientInfo(self.clients[token], True)

    def sendClientInfo(self, info, new_client):
        '''Send a single information about a new or lost client'''
        # Specify wether this information is about a new or lost client
        if new_client:
            SEmsg = b'CI+'
            log_msg = 'CI+ '
        else:
            SEmsg = b'CI-'
            log_msg = 'CI- '

        # Adding token and public key
        SEmsg += info.token + info.pubkey
        log_msg += toHex(info.token) + ' pubkey'

        # Specifying wether this client is the keymaster
        if self.master_token == info.token:
            SEmsg += b'M'
            log_msg += ' M'
        else:
            SEmsg += b'S'
            log_msg += ' S'

        # Specifying wether this client is afk
        if info.afk:
            SEmsg += b'T'
            log_msg += ' T '
        else:
            SEmsg += b'F'
            log_msg += ' F '

        # Adding name
        SEmsg += info.name.encode()
        log_msg += info.name
        self.logger.log('Client info: ' + log_msg)
        # Sending information to all users
        self.send(SEmsg)

    def sendServerMessage(self, msg):
        '''Send a server message that will be displayed by the clients'''
        self.logger.log('Broadcast: ' + msg)
        SEmsg = SERVER_MESSAGE + toBytes(msg)
        self.send(SEmsg)

    def kick(self, identity):
        # Todo
        pass

    def renewUserKeys(self):
        '''Forcing all clients to renew their session key'''
        self.logger.log('Renewing the user encryption...')
        self.logger.log('Making all users forget their keys.')
        # Letting all users forget ther session key
        self.send(FORGET_KEY)
        self.logger.log('Sending client list.')
        # Sending the client list will force all clients to check who the master
        # is. Since all user forgot their old session key they are forced to
        # send new key requests from the master.
        self.sendClientList()

    def ping(self, token):
        '''Send a ping to a single client'''
        self.logger.log('Sending ping to ' + toHex(token))
        self.send(PING, token)

    def pong(self, token):
        '''Renews a clients "last pong"'''
        self.clients[token].last_pong = time()

    def checkToken(self, user_msg, sock):
        '''Checks the provided source token for a message'''
        try:
            try:
                msg = self.encryption_Handler.AESDecrypt(user_msg[:128])
                session_id = msg[:TOKEN_SIZE]
                self.logger.log('Checking token: ' + toHex(session_id))
                msg = msg[TOKEN_SIZE:]
                dest_session_id = msg[:TOKEN_SIZE]
                msg = msg[TOKEN_SIZE:]
                operation = msg[:3]
                client_info = self.clients[session_id]
            except:
                # If the 'clients' list has an index error this exception will be raised.
                raise VerificationError('The client sent a false session-id.')
            if sock == client_info.con:
                self.logger.log('Correct token: ' + toHex(session_id))
                # If an AFK report was sent change the AFK status
                if operation == AFK_REPORT:
                    client_info.afk = not client_info.afk
                else:
                    client_info.afk = False
                return True, dest_session_id, operation, session_id
            else:
                raise VerificationError('The client tried to fake their identity.')
        except VerificationError as err:
            self.logger.log('Incorrect token: ' + err.value, True)
            self.sendServerMessage(client_info.name + ' will be kicked! Reason: ' + err.value)
            self.kick(client_info.name)
            return False, None, None, None
Ejemplo n.º 6
0
    def handleNewClient(self):
        '''Handles the log-in process for a new client'''
        def signed_send(msg, ehandler, client, length=512):
            signature = ehandler.sign(msg)
            e_msg = ehandler.AESEncrypt(msg, length)
            client.sendall(e_msg + signature)

        def verified_recv(ehandler, client, length=512):
            length += 512
            msg = client.recv(length)
            signature = msg[length-512:]
            msg = msg[:length-512]
            user_msg = ehandler.AESDecrypt(msg)
            if not ehandler.verify(user_msg, signature):
                raise VerificationError('Wrong signature from client!')
            return user_msg

        try:
            client, addr = self.server.socket.accept()
            self.logger.log('New Client:' + str(addr))
            #
            # This EncryptionHandler is only used for the
            # login of one user.
            #
            #e = EncryptionHandler(logger=self.logger, name='LoginEH')
            e = EncryptionHandler()
            e.importPrivateKey(self.server.encryption_Handler.exportPrivateKey())
            #
            # Sending the public RSA key and a salt for hashing the
            # password.
            #
            self.logger.log('Sending pubkey and salt.')
            salt = e.random(128)
            client.sendall(salt + e.exportPublicKey())
            #
            # The client sent us multiple information:
            # -The hashed password (64 Bytes)
            # -His AES-key we will be using for this login (32 Bytes)
            # -His AES-IV (16 Bytes)
            # -His RSA-public key (550 Bytes)
            # Because all this information was sent at once we can be sure
            # that only a user already knowing the serverpassword sent it to us.
            # Since the asymmetric decryption will fail, if only single bytes
            # have been changed we can be sure, that this information is 
            # valid and has not been changed by a MITM-attacker.
            #
            client_info = client.recv(1062)
            self.logger.log('Recieved clientinfo.')
            client_public_key = client_info[512:]
            e.importPublicKey(client_public_key)
            client_info = e.RSADecrypt(client_info[:512])
            client_password = client_info[:64]
            aes_key = client_info[64:96]
            aes_iv = client_info[96:]
            if client_password != pbkdf2(64, self.server.server_password.encode(), salt):
                #
                # A wrong password has been sent. The client is rejected.
                #
                self.logger.log(addr[0] + ' entered the wrong password and was rejected.')
                client.sendall(bytes([0]))
                client.close()
            else:
                #
                # The password was right and the login can continue.
                #
                client.sendall(bytes([1]))
                #
                # Using the clients AES-key and AES-IV from now on.
                #
                e.setAESObject(aes_key, aes_iv)
                #
                # The login proceeds with AES256 instead of PKCS1_OAEP.
                # Names are exchanged. The clients name needs to be
                # formatted properly. ',' and ';' are not allowed because
                # they are used in the client list. If a name already exists
                # a '.' is added. If simply no name was given the client gets
                # the name 'Anonymous'.
                #
                client_name = verified_recv(e, client)
                client_name = client_name.replace(b'\0',b'').replace(b'\\\\', b'').strip().decode()
                self.logger.log('Recieved client-name: ' + client_name)
                if len(client_name) == 0:
                    client_name = 'Anonymous'
                ctr = 1
                modified_client_name = client_name
                name_list = self.server.getNameList()
                while modified_client_name in name_list:
                    modified_client_name = client_name + ' (' + str(ctr) + ')'
                    ctr += 1
                client_name = modified_client_name
                self.logger.log('Modified client-name: ' + client_name)
                signed_send(self.server.server_name.encode(), e, client)
                #
                # The clients version is transmitted.
                #
                client_ver = verified_recv(e, client).decode()
                self.logger.log(client_name + ' uses ' + client_ver)
                #
                # The servers AES-key is sent.
                #
                key = self.server.encryption_Handler.__aeskey__
                iv = self.server.encryption_Handler.__aes__.IV
                self.logger.log('Sending key ({}) and IV ({})'.format(toHex(key), toHex(iv)))
                signed_send(key + iv, e, client)
                #
                # Creating and sending the clients session-id and the servers id aswell.
                #
                session_id = e.random(TOKEN_SIZE, client_name)
                while session_id in self.server.getTokenList() or session_id == BROADCAST_TOKEN:
                    session_id = e.random(TOKEN_SIZE, client_name)
                self.logger.log('Clients session-id: {}'.format(toHex(session_id)))
                signed_send(session_id + self.server.token, e, client)
                #
                # The client is fully accepted and part of the normal routine.
                #
                self.clients.append(client) # Add socket to the handler

                # Add client to the server
                client = Client(client, client_name, session_id, client_public_key)
                self.server.clients[session_id] = client
                # If the client is the first on the Server he's the master
                if self.server.master_token is None:
                    self.logger.log('Client is the key-master.')
                    self.server.master_token = session_id
                    self.logger.log('New master-token: {}'.format(toHex(session_id)))
                #self.server.to_checker.addClient(client)
                msg = '{} is connected'.format(client_name)
                self.logger.log(msg)
                self.server.send(msg)
                sleep(0.05)
                self.server.sendClientList()
        except VerificationError as err:
            client.close()
            self.logger.log('Error verifying client: ' + err.value)