def handleKeyAdvertisementServer(client, data, privDhVal=None): print("key ad received") # DEBUG validKeyHashes = None try: sessionKey = client.getSessionKey() unencryptedData = AES.decrypt(data=data, key=sessionKey) msg = Message.fromBytes(unencryptedData) validKeyHashes = msg.getObjectKeyHashes() if validKeyHashes == False or validKeyHashes == None: # Not a valid KEY_ADVERTISEMENT. return False except: # Not a proper message, likely wrong level of encryption raise if data != -1: return False state = client.getConnectionState() # Update server state and calculate session key if state == ServerState.KEYS_ADVERTISED: client.setConnectionState(ServerState.DATA_EXCHANGE) client.setObjectKeyHashes(validKeyHashes) sendMsg = Message(MessageType.KEY_ADVERTISEMENT_ACK) sendMsgBytes = AES.encrypt(data=sendMsg.toBytes(), key=sessionKey) sock = client.getSocket() sendBytes(client, sendMsgBytes) print("key ad sent") # DEBUG return True
def handleShutdown(client): client.setConnectionState(ServerState.SHUTDOWN_SENT) sock = client.getSocket() sock.settimeout(RESPONSE_TIMEOUT) maxResendCount = 10 resendCount = 0 sessionKey = client.getSessionKey() sendMsg = Message(MessageType.SHUTDOWN_CLOSEE_ACK) sendMsgBytes = AES.encrypt(data=sendMsg.toBytes(), key=sessionKey) sendBytes(client, sendMsgBytes) while client.getConnectionState( ) != ServerState.SHUTDOWN_COMPLETE and resendCount < maxResendCount: try: data = sock.recv(1024) except: resendCount += 1 continue if data == -1: sendBytes(client, sendMsgBytes) else: unencryptedData = AES.decrypt(data=data, key=sessionKey) msg = Message.fromBytes(unencryptedData) if msg.type == MessageType.SHUTDOWN_CLOSER_ACK: client.setConnectionState(ServerState.SHUTDOWN_COMPLETE) else: sendBytes(client, sendMsgBytes) resendCount += 1
def handleObjectRequestAck(server, data): status = None reqNum = None try: unencryptedData = AES.decrypt(data=data, key=server.getSessionKey()) msg = Message.fromBytes(unencryptedData) status = msg.getStatus() reqNum = msg.getRequestNumber() if status in {False, None} or reqNum in {False, None}: return (False, None, None) except: return (False, None, None) if not server.checkRequestNumberUsed(reqNum): return (False, None, None) if server.getRequestNumberState( reqNum) < DataExchangeState.EXCHANGE_COMPLETE: server.setRequestNumberState(reqNum, DataExchangeState.EXCHANGE_COMPLETE) sock = server.getSocket() sessionKey = server.getSessionKey() sendMsgData = {"requestNum": reqNum} sendMsg = Message(MessageType.DATA_ACK, sendMsgData) sendMsgBytes = AES.encrypt(data=sendMsg.toBytes(), key=sessionKey) sendBytes(server, sendMsgBytes) return (True, status, reqNum)
def handleKeyAdvertisement(server, data): sock = server.getSocket() keyHashes = None try: unencryptedData = AES.decrypt(data=data, key=server.getSessionKey()) msg = Message.fromBytes(unencryptedData) keyHashes = msg.getObjectKeyHashes() if keyHashes == False or keyHashes == None: return False except: raise if data != -1: # Not a timeout return False if server.getConnectionState() == ClientState.DIFFIE_HELLMAN_SENT: server.setConnectionState(ClientState.KEYS_ADVERTISED) server.setObjectKeyHashes(keyHashes) allowedKeys = list(objectKeyDict.keys()) sendMsgData = {"keys": allowedKeys} sendMsg = Message(MessageType.KEY_ADVERTISEMENT, sendMsgData) sendMsgBytes = AES.encrypt(sendMsg.toBytes(), server.getSessionKey()) sendBytes(server, sendMsgBytes) return True
def handleDiffieHellmanResponse(client, data, privDhVal=None): dhVal = None try: clientPubKey = client.getPubKey() encryptedData, signature = RSA.separateSignature(data, clientPubKey) unencryptedData = RSA.decrypt(data=encryptedData, key=ownPrivKey) if not RSA.checkSignature(unencryptedData, clientPubKey, signature): return False msg = Message.fromBytes(unencryptedData) dhVal = msg.getDiffieHellmanValue() if dhVal == False or dhVal == None: # Not a valid DIFFIE_HELLMAN_RESPONSE. Probably an encrypted message that start with the right number return False except: # Not a proper message, likely wrong level of encryption if data != -1: return False state = client.getConnectionState() # Update server state and calculate session key if state == ServerState.CONNECT_RESPONSE_SENT: client.setConnectionState(ServerState.KEYS_ADVERTISED) sessionKey = DH.createDiffieHellmanKey(dhVal, privDhVal) client.setSessionKey(sessionKey) sessionKey = client.getSessionKey() allowedKeys = list(objectKeyDict.keys()) sendMsgData = {"keys": allowedKeys} sendMsg = Message(MessageType.KEY_ADVERTISEMENT, sendMsgData) sendMsgBytes = AES.encrypt(data=sendMsg.toBytes(), key=sessionKey) sock = client.getSocket() sendBytes(client, sendMsgBytes)
def handleDataResponse(server, msg): reqNum = msg.getRequestNumber() keyHash = msg.getObjectKeyHash() dataHash = msg.getObjectDataHash() data = msg.getObjectData() objectName = msg.getObjectName() if reqNum in {False, None} or keyHash in {False, None} or dataHash in { False, None } or data in {False, None} or objectName in {False, None}: return False if server.checkRequestNumberUsed(reqNum) == False: return False requestData = server.getRequestNumberData(reqNum) if requestData == None or objectName != requestData['name']: return False key = objectKeyDict.get(keyHash) key = base64.b64decode(key) if key == None: return False unencryptedDataHash = AES.decrypt(data=dataHash, key=key) unencryptedData = AES.decrypt(data=data, key=key) preHashValue = bytearray(unencryptedData) + bytearray(objectName, "ascii") if getHash(bytes( preHashValue)) != unencryptedDataHash: # Not the correct object return False if server.getRequestNumberState(reqNum) == DataExchangeState.REQUEST_SENT: saveObject(unencryptedData, objectName, server.getSaveFileLocation()) server.setRequestNumberState(reqNum, DataExchangeState.EXCHANGE_COMPLETE) sock = server.getSocket() sessionKey = server.getSessionKey() sendMsgData = {"requestNum": reqNum} sendMsg = Message(MessageType.DATA_ACK, sendMsgData) sendMsgBytes = AES.encrypt(data=sendMsg.toBytes(), key=sessionKey) sendBytes(server, sendMsgBytes) return True
def handleKeyAdvertisementAck(server, data): try: unencryptedData = AES.decrypt(data=data, key=server.getSessionKey()) msg = Message.fromBytes(unencryptedData) if msg.getType() != MessageType.KEY_ADVERTISEMENT_ACK: return False except: return False print("key ad recv") # DEBUG if server.getConnectionState() == ClientState.KEYS_ADVERTISED: server.setConnectionState(ClientState.DATA_EXCHANGE)
def initiateShutdown(server): server.setConnectionState(ClientState.SHUTDOWN_SENT) sock = server.getSocket() sock.settimeout(RESPONSE_TIMEOUT) maxResendCount = 10 resendCount = 0 sessionKey = server.getSessionKey() sendMsg = Message(MessageType.SHUTDOWN_REQUEST) sendMsgBytes = AES.encrypt(data=sendMsg.toBytes(), key=sessionKey) sendBytes(server, sendMsgBytes) while server.getConnectionState( ) != ClientState.SHUTDOWN_COMPLETE and resendCount < maxResendCount: data = None try: data = sock.recv(1024) except socket.timeout: data = -1 if data == -1: sendBytes(server, sendMsgBytes) else: unencryptedData = AES.decrypt(data=data, key=sessionKey) msg = Message.fromBytes(unencryptedData) if msg.type == MessageType.SHUTDOWN_CLOSEE_ACK: server.setConnectionState(ClientState.SHUTDOWN_COMPLETE) sendMsg = Message(MessageType.SHUTDOWN_CLOSER_ACK) sendMsgBytes = AES.encrypt(data=sendMsg.toBytes(), key=sessionKey) sendBytes(server, sendMsgBytes) else: sendBytes(server, sendMsgBytes) resendCount += 1 sock.close()
def dataExchangeLoop(client): sock = client.getSocket() sessionKey = client.getSessionKey() sock.settimeout(RESPONSE_TIMEOUT) connectionTimeout = 5 lastMessageTime = time() while client.getConnectionState() == ServerState.DATA_EXCHANGE and time( ) < lastMessageTime + connectionTimeout: try: data = sock.recv(1024) except socket.timeout: continue msg = None type = None try: unencryptedData = AES.decrypt(key=sessionKey, data=data) msg = Message.fromBytes(unencryptedData) type = msg.getType() if type != MessageType.SHUTDOWN_REQUEST and type != MessageType.OBJECT_REQUEST and type != MessageType.DATA_ACK and type != KEY_ADVERTISEMENT: continue lastMessageTime = time() except: # Probably an OBJECT_REQUEST try: msg = Message.fromBytes(data) type = msg.getType() if type == MessageType.OBJECT_REQUEST: handleObjectRequest(client, msg) except: # An invalid message continue if type == MessageType.SHUTDOWN_REQUEST: handleShutdown(client) elif type == MessageType.DATA_ACK: handleDataAck(client, msg) elif type == MessageType.KEY_ADVERTISEMENT: handleKeyAdvertisementServer(client, data)
def handleObjectRequest(client, msg): # TODO add an objReqAck print("objreq recv") # DEBUG reqNum = msg.getRequestNumber() target = msg.getTargetObject() keyHash = msg.getRequestedObjectKeyHash() sock = client.getSocket() # Make sure all values exist if reqNum == False or reqNum == None or target == False or target == None or keyHash == False or keyHash == None: return if not isValidRequestNumber(reqNum) or not keyHash in objectKeyDict.keys( ): # TODO create func and decide what makes a request number return elif not client.checkRequestNumberUsed(reqNum): # A new request client.setRequestNumberState(reqNum, DataExchangeState.DATA_SENT) objectData = retrieveData(target, client.getLoadFileLocation()) objectKey = objectKeyDict[keyHash] # Send an object request ack if either fails if objectData == None: # TODO or whatever fail value is for obtainData sessionKey = client.getSessionKey() sendMsgData = { "status": DataExchangeStatus.OBJ_NOT_FOUND, "requestNum": reqNum } sendMsg = Message(MessageType.OBJECT_REQUEST_ACK, sendMsgData) sendMsgBytes = AES.encrypt(data=sendMsg.toBytes(), key=sessionKey) sendBytes(client, sendMsgBytes) print("Requested file not found: '{}'".format(target)) return elif objectKey == None: sessionKey = client.getSessionKey() sendMsgData = { "status": DataExchangeStatus.UNKNOWN_KEY, "requestNum": reqNum } sendMsg = Message(MessageType.OBJECT_REQUEST_ACK, sendMsgData) sendMsgBytes = AES.encrypt(data=sendMsg.toBytes(), key=sessionKey) sendBytes(client, sendMsgBytes) print("Object key unknown for requested file: '{}'".format(target)) return objectKey = base64.b64decode(objectKey) encryptedObjectData = AES.encrypt(data=objectData, key=objectKey) preHashValue = bytearray(objectData) + bytearray(target, "ascii") objectHash = getHash(preHashValue) # TODO make it actually append encryptedObjectHash = AES.encrypt(data=bytes(objectHash), key=objectKey) messageData = { "keyHash": keyHash, "dataHash": encryptedObjectHash, "data": encryptedObjectData, "objectName": target, "requestNum": reqNum, "expiration": time() + 3600 } client.setRequestNumberData( reqNum, messageData) # Save the data to avoid recomputing for resends sendMsg = Message(MessageType.DATA_MESSAGE, messageData) sendMsgBytes = sendMsg.toBytes() sendBytes(client, sendMsgBytes) print("File found and sent: '{}'".format(target)) elif client.getRequestNumberState( reqNum) == DataExchangeState.DATA_SENT: # A resend request messageData = client.getRequestNumberData(reqNum) sendMsg = Message(MessageType.DATA_MESSAGE, messageData) sendMsgBytes = sendMsg.toBytes() sendBytes(client, sendMsgBytes)