def __init__(self): self.rsa = RSAClass() #generate the Public Private key pair for this client self.public_key, self.private_key = self.rsa.generate_keys() # read in the Public key of the Server from XML File self.pubKey = chilkat.CkPublicKey() self.pubKey.LoadXmlFile("Serverpublickey.xml") self.ServerPublicKey = self.pubKey.getXml() #objects for hashing and diffie hellman self.md5_crypt = chilkat.CkCrypt2() self.hashcrypt = chilkat.CkCrypt2() self.dhAlice = chilkat.CkDh() self.md5_crypt.put_EncodingMode("hex") # Set the hash algorithm: self.md5_crypt.put_HashAlgorithm("md5") self.hashcrypt.put_EncodingMode("hex") self.hashcrypt.put_HashAlgorithm("md5") # Unlock components above self.UnlockComponents() #create a oscket and connect to the server self.client = socket(AF_INET, SOCK_STREAM) self.client.connect(ADDR) # setup an AES object with cipher block chaining, 128-bit key, padding size and format self.a = AESClass("cbc", 128, 0, "hex") # source port of Client for use in communications later self.client_src_port = self.client.getsockname()[1]
def __init__(self, address=('localhost', 0)): asyncore.dispatcher.__init__(self) #import the Servers Keys, Saved to XML in FileSystem privkey = chilkat.CkPrivateKey() privkey.LoadXmlFile("Serverprivatekey.xml") self.ServerPrivateKey = privkey.getXml() #create RSA object self.rsa = RSAClass() #Chilkat object forCreating hashes self.hashcrypt = chilkat.CkCrypt2() success = self.hashcrypt.UnlockComponent("T12302015Crypt_sHyDCAFgIR1v") if (success != True): print(hself.ashcrypt.lastErrorText()) sys.exit() # setting encoding mode for hashing algorithm self.hashcrypt.put_EncodingMode("hex") self.hashcrypt.put_HashAlgorithm("md5") # setup data for Diffie Hellman Key exchange self.dhBob = chilkat.CkDh() success = self.dhBob.UnlockComponent("T12302015Diffie_eegQ20BTIR5q") if (success != True): print(self.dhBob.lastErrorText()) sys.exit() self.dhBob.UseKnownPrime(2) self.p = self.dhBob.p() self.g = self.dhBob.get_G() self.eBob = self.dhBob.createE(256) #initially set the the AES object with cipher block chaining 128bit self.aesObj = AESClass("cbc",128,0,"hex") self.inital_setup = "0" #store client IDS and nonces # nonces used in replay protection self.CLIENT_ID_STORE ={} self.CLIENT_ID = [] #placeholders fo the keys (session and shared the same really) self.sharedKey = None self.sessionkey = None # self.set_reuse_addr() #bind to socket and listen self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.bind(address) #print ("Address Server", address) # accept with no backlog # syncore dispatcher handles it all self.listen(1) #store connected clients in LIST self.remote_clients = []
def __init__(self): self.rsa = RSAClass() #generate the Public Private key pair for this client self.public_key, self.private_key = self.rsa.generate_keys() # read in the Public key of the Server from XML File self.pubKey = chilkat.CkPublicKey() self.pubKey.LoadXmlFile("Serverpublickey.xml") self.ServerPublicKey = self.pubKey.getXml() #objects for hashing and diffie hellman self.md5_crypt = chilkat.CkCrypt2() self.hashcrypt = chilkat.CkCrypt2() self.dhAlice = chilkat.CkDh() self.md5_crypt.put_EncodingMode("hex") # Set the hash algorithm: self.md5_crypt.put_HashAlgorithm("md5") self.hashcrypt.put_EncodingMode("hex") self.hashcrypt.put_HashAlgorithm("md5") # Unlock components above self.UnlockComponents() #create a oscket and connect to the server self.client = socket(AF_INET, SOCK_STREAM) self.client.connect(ADDR) # setup an AES object with cipher block chaining, 128-bit key, padding size and format self.a = AESClass("cbc",128,0,"hex") # source port of Client for use in communications later self.client_src_port = self.client.getsockname()[1]
def run(self): #extract the path and private flag from shared memory file_path = self.sharedMem["file_path"] private = self.sharedMem["private"] #AES MODE if self.mode == 1: #SOCKET create, connect, and send a white space left justified string s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(('localhost', self.dst_port)) paddedFile_path = file_path.ljust(1024) print "len padded file path ", paddedFile_path s.send(paddedFile_path) #open file for sending file_f = open(file_path, "rb") #block transfer block = file_f.read(1024) #get file size filesize = int(os.stat(file_path).st_size) #count blocks blockCounter = len(block) while (block): #calc percentage calc = (float(blockCounter)/float(filesize))*float(100) print calc #convert binary the HEX STRING hexblock=binascii.hexlify(block) #Encypt the Hex String block = self.aes.enc_str(hexblock) #send block s.send(block) #read another for the file block = file_f.read(1024) #add to the counter blockCounter += len(block) print "file sent" #close file file_f.close() print "AES FILETRANSFER COMPLETE" wx.CallAfter(self.text_send.AppendText, "\n" + t() + "AES FILETRANSFER COMPLETE" + "\n") s.close() #RSA MODE - same as above but with RSA and Private mode if self.mode == 2: rsa = RSAClass() s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.connect(('localhost', self.dst_port)) #receive the public key for encryption FSPUBLIC = s.recv(243) #if private mode if private == True: #send this flag to P2P Read Thread of the target client s.send("1") #private message extract shared mem privatemessage = self.sharedMem["privatemessage"] enc_private_message = rsa.encrypt_text(str(privatemessage), FSPUBLIC) enc_private_message = enc_private_message.ljust(2048) s.send(enc_private_message) wx.CallAfter(self.text_send.AppendText, "\n" + t() + "RSA privatemessage COMPLETE" + "\n") #set private to off self.sharedMem["private"] = False else: s.send("0") paddedFile_path = file_path.ljust(1024) print "len padded file path ", paddedFile_path s.send(paddedFile_path) #get the total size of file in bytes filesize = int(os.stat(file_path).st_size) file_f = open(file_path, "rb") block = file_f.read(1024) blockCounter = len(block) #same as prior while (block): calc = (float(blockCounter)/float(filesize))*float(100) print calc hexblock=binascii.hexlify(block) block = rsa.encrypt_text(hexblock, FSPUBLIC) s.send(block) block = file_f.read(1024) blockCounter += len(block) file_f.close() s.close() # s.send(self.data) print "RSA FILETRANSFER COMPLETE" wx.CallAfter(self.text_send.AppendText, "\n" + t() + "RSA FILETRANSFER COMPLETE" + "\n") # terminate the thread def stop(self): print "Trying to stop thread " if self.process is not None: self.process.terminate() self.process = None
def run(self): print "size of public_key", len(str(self.public_key)) # create a new socket and Bind to a Random free port (0) s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.bind(('localhost', 0)) #get the address and store so it can be returned newSocketAddress = s.getsockname() self.newReadSocketAddress = newSocketAddress import math suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] def human_size(nbytes): rank = int((math.log10(nbytes)) / 3) rank = min(rank, len(suffixes) - 1) human = nbytes / (1024.0 ** rank) f = ('%.2f' % human).rstrip('0').rstrip('.') return '%s %s' % (f, suffixes[rank]) # if the mode is AES if self.mode == 1: #Wait to accept one client s.listen(1) print "@@@@@@@@@@@@@@@@@@@@@@@@-SECOND SOCKET CREATED AES-@@@@@@@@@@@@@@@@@@@@@@" self.socket = s # accept the client as a new socket sock sock, addr = self.socket.accept() #receive the original file path, padded with white space t0 1024 characters self.original_file_path = sock.recv(1024) #strip the whitespace padding unpaddedOriginal = self.original_file_path.strip() print "unpaddedOriginal", unpaddedOriginal, len(unpaddedOriginal) #split the path and name, then rename with "_txCopy" path, filename_ext = os.path.split(unpaddedOriginal) filename, extension = os.path.splitext(filename_ext) filename = filename + "_txCopy" + extension file_f = open(filename,'wb') #open in binary block = sock.recv(2752) blockCounter = len(block) while (block): print "RECIEVED", human_size(blockCounter) block=self.aes.dec_str(block) unhexblock=binascii.unhexlify(block) file_f.write(unhexblock) block=sock.recv(2752) blockCounter += len(block) wx.CallAfter(self.text_send.AppendText, "\n" + t() + "AES FILETRANSFER RECIEVED" + "\n") print "!!!!!!!!!!!!!!!!!! FILETRANSFER COMPLETED !!!!!!!!!!!!!!!!!!!!!!!!!!!!!" file_f.close() sock.close() print "@@@@@@@@@@@@@@@@@@@@@@@ new socket closed @@@@@@@@@@@@@@@@@@@@@@@@@@@@" # The same as above but with RSA if self.mode == 2: s.listen(1) print "@@@@@@@@@@@@@@@@@@@@@@@@-SECOND SOCKET CREATED RSA-@@@@@@@@@@@@@@@@@@@@@@" self.socket = s sock, addr = self.socket.accept() #Send This clients Public key to the calling client sock.send(self.public_key) rsa = RSAClass() #receive if this is private message mode private = sock.recv(1) if private == "1": print "ENTERING PRIAVTE MODE" privatemessage = sock.recv(2048) privatemessage = privatemessage.strip() privatemessage = rsa.decrypt_text(privatemessage, self.private_key) #append the private received message to the chat window wx.CallAfter(self.text_send.AppendText, "\n" + t() + "RSA_PRIVATE:"+privatemessage + "\n") else: self.original_file_path = sock.recv(1024) # print "self.original_file_path", self.original_file_path, len(self.original_file_path) unpaddedOriginal = self.original_file_path.strip() print "unpaddedOriginal", unpaddedOriginal, len(unpaddedOriginal) path, filename_ext = os.path.split(unpaddedOriginal) filename, extension = os.path.splitext(filename_ext) filename = filename + "_txCopy" + extension file_f = open(filename,'wb') # data = sock.recv(1024) block=sock.recv(4608) #----receiving & decrypting------- blockCounter = len(block) while (block): print "RECIEVED ", human_size(blockCounter) block = rsa.decrypt_text(block, self.private_key) unhexblock=binascii.unhexlify(block) file_f.write(unhexblock) block=sock.recv(4608) blockCounter += len(block) wx.CallAfter(self.text_send.AppendText, "\n" + t() + "RSA FILETRANSFER RECIEVED" + "\n") print "!!!!!!!!!!!!!!!!!! FILETRANSFER COMPLETED !!!!!!!!!!!!!!!!!!!!!!!!!!!!!" file_f.close() sock.close() print "@@@@@@@@@@@@@@@@@@@@@@@ new socket closed @@@@@@@@@@@@@@@@@@@@@@@@@@@@"
class Client: """Class for a user of the chat client.""" def __init__(self): self.rsa = RSAClass() #generate the Public Private key pair for this client self.public_key, self.private_key = self.rsa.generate_keys() # read in the Public key of the Server from XML File self.pubKey = chilkat.CkPublicKey() self.pubKey.LoadXmlFile("Serverpublickey.xml") self.ServerPublicKey = self.pubKey.getXml() #objects for hashing and diffie hellman self.md5_crypt = chilkat.CkCrypt2() self.hashcrypt = chilkat.CkCrypt2() self.dhAlice = chilkat.CkDh() self.md5_crypt.put_EncodingMode("hex") # Set the hash algorithm: self.md5_crypt.put_HashAlgorithm("md5") self.hashcrypt.put_EncodingMode("hex") self.hashcrypt.put_HashAlgorithm("md5") # Unlock components above self.UnlockComponents() #create a oscket and connect to the server self.client = socket(AF_INET, SOCK_STREAM) self.client.connect(ADDR) # setup an AES object with cipher block chaining, 128-bit key, padding size and format self.a = AESClass("cbc", 128, 0, "hex") # source port of Client for use in communications later self.client_src_port = self.client.getsockname()[1] def UnlockComponents(self): success = self.md5_crypt.UnlockComponent("T12302015Crypt_sHyDCAFgIR1v") if (success != True): print(self.md4_crypt.lastErrorText()) sys.exit() success = self.hashcrypt.UnlockComponent("T12302015Crypt_sHyDCAFgIR1v") if (success != True): print(self.hashcrypt.lastErrorText()) sys.exit() success = self.dhAlice.UnlockComponent("T12302015Diffie_eegQ20BTIR5q") if (success != True): print(self.dhAlice.lastErrorText()) sys.exit() def setUpClient(self): #random nonce generated for the cient # seeded (probally with system time) to ensure new nonce generation # well as much as pseudorandom can ensure random.seed() nonce = random.randrange(10000000000000, 99999999999999) # generate an ID dictionary for the client, passing its # public-key and nonce to the server # serializing the object # hashing it + concatenating the hash to ther serialized data # then encypting with the servers public to ensure the nonce # cannot be intercepted # send to server firstID = {'nonce': nonce, 'public_key': self.public_key} pid = pickle.dumps(firstID) hashStr = self.md5_crypt.hashStringENC(str(nonce)) finalID = pid + hashStr encyptedpayload = self.rsa.encrypt_text(finalID, self.ServerPublicKey) self.client.send(encyptedpayload) # recieve the Responce from the server with orginal client nonce # and the servers nonce challange_Resp = self.client.recv(1024) # decypt with the clients public key challange_Resp = self.rsa.decrypt_text(challange_Resp, self.private_key) # decypt with the servers private - verifys - because nonces will be mangled # if there a different private RSA used - It is assumed server only has this key challange_Resp = self.rsa.decrypt_with_public(challange_Resp, self.ServerPublicKey) # remove the Hash of the orginal serialized object - 32 Characters from end of message h = challange_Resp[-32:] # remove the serialized object - to the last 32 characters of the data challange_Resp = challange_Resp[:-32] # rehash this object h2 = self.md5_crypt.hashStringENC(challange_Resp) # de-serialized the object back to a python dictionary challange_Resp = pickle.loads(challange_Resp) # extract the returned nonce-1, check if valid, close socket and exit if not nonce_1 = challange_Resp["cnonce"] if h == h2 and nonce == nonce_1: print "\n$$$$$$$$$$$$$$$$$$$$$$$$$$$$" print "Challange Integrity Verified" print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n" else: print "Integrity Challange Failed - closing connection" client.close() sys.exit(0) # extract the server nonce snonce = challange_Resp["snonce"] #check to see if a "Master Client" has setup the CHatroom #if not then initate the Diffie-Hellman Key exchange with the server # if it has happened retieve the Session-key from the server # have to have exact bytes(sync issues) !!!!!!!!!!!!!!!!!!!! inital_setup = self.client.recv(1) print "inital_setup has occured before = ", inital_setup serverKey = None if inital_setup == "1": print "attempt to recv server key" serverKey = self.client.recv(1280) serverKey = self.rsa.decrypt_text(serverKey, self.private_key) serverKey = self.rsa.decrypt_with_public(serverKey, self.ServerPublicKey) h = serverKey[-32:] serverKey = serverKey[:-32] h2 = self.md5_crypt.hashStringENC(serverKey) serverKey = pickle.loads(serverKey) if h == h2 and serverKey["cnonce"] == nonce and serverKey[ "snonce"] == snonce: sk = serverKey["aes_key"] print "serverSessionKey", sk print "setting serverSessionKey" self.a.set_sessionkey(sk) iv = self.a.getCrypt().hashStringENC(sk) self.a.setIv(iv) else: print "Integrity Mismatch" client.close() sys.exit(0) # Recieved "Pickled" object on socket - ie serialised to String # Deserialize Data recieved back into # Python dictionary then remove the objects else: try: pk1 = self.client.recv(1792) pk2 = self.client.recv(1792) pk1 = self.rsa.decrypt_text(pk1, self.private_key) pk2 = self.rsa.decrypt_text(pk2, self.private_key) defragment = pk2 + pk1 defragment = self.rsa.decrypt_with_public( defragment, self.ServerPublicKey) h = defragment[-32:] defragment = defragment[:-32] h2 = self.md5_crypt.hashStringENC(defragment) dictObj = pickle.loads(defragment) if h == h2 and dictObj["cnonce"] == nonce and dictObj[ "snonce"] == snonce: p = dictObj["p"] g = dictObj["g"] g = int(g) eBob = dictObj["e"] else: print "Integrity Mismatch" client.close() sys.exit(0) except: print "fails to recieve Diffie-hellman data" sys.exit(0) # use the information for Diffie-hellman cleint side success = self.dhAlice.SetPG(p, g) if (success != True): print("P is not a safe prime") sys.exit() eAlice = self.dhAlice.createE(256) eAlice = self.rsa.encrypt_text(eAlice, self.ServerPublicKey) print "size of eAlice", len(str(eAlice)) self.client.send(eAlice) #Alice's shared secret kAlice = self.dhAlice.findK(eBob) print("Alice's shared secret (should be equal to Bob's)") print(kAlice) sessionkey = self.hashcrypt.hashStringENC(kAlice) print "SessionKey", sessionkey self.a.set_sessionkey(sessionkey) iv = self.a.getCrypt().hashStringENC(sessionkey) self.a.setIv(iv) # print "serverKey testing" # print type(serverKey) # print len(str(serverKey)) # depending on if this is a first setup or not # use the key (ie same key)for AES ---- one that is sent in open # would have to use a digital envelope of the like to achieve this properly # setup this sides AES object self.a.setupAES() print "-------------AES KEY-----------------" print self.a.get_key()
def run(self): #extract the path and private flag from shared memory file_path = self.sharedMem["file_path"] private = self.sharedMem["private"] #AES MODE if self.mode == 1: #SOCKET create, connect, and send a white space left justified string s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('localhost', self.dst_port)) paddedFile_path = file_path.ljust(1024) print "len padded file path ", paddedFile_path s.send(paddedFile_path) #open file for sending file_f = open(file_path, "rb") #block transfer block = file_f.read(1024) #get file size filesize = int(os.stat(file_path).st_size) #count blocks blockCounter = len(block) while (block): #calc percentage calc = (float(blockCounter) / float(filesize)) * float(100) print calc #convert binary the HEX STRING hexblock = binascii.hexlify(block) #Encypt the Hex String block = self.aes.enc_str(hexblock) #send block s.send(block) #read another for the file block = file_f.read(1024) #add to the counter blockCounter += len(block) print "file sent" #close file file_f.close() print "AES FILETRANSFER COMPLETE" wx.CallAfter(self.text_send.AppendText, "\n" + t() + "AES FILETRANSFER COMPLETE" + "\n") s.close() #RSA MODE - same as above but with RSA and Private mode if self.mode == 2: rsa = RSAClass() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('localhost', self.dst_port)) #receive the public key for encryption FSPUBLIC = s.recv(243) #if private mode if private == True: #send this flag to P2P Read Thread of the target client s.send("1") #private message extract shared mem privatemessage = self.sharedMem["privatemessage"] enc_private_message = rsa.encrypt_text(str(privatemessage), FSPUBLIC) enc_private_message = enc_private_message.ljust(2048) s.send(enc_private_message) wx.CallAfter(self.text_send.AppendText, "\n" + t() + "RSA privatemessage COMPLETE" + "\n") #set private to off self.sharedMem["private"] = False else: s.send("0") paddedFile_path = file_path.ljust(1024) print "len padded file path ", paddedFile_path s.send(paddedFile_path) #get the total size of file in bytes filesize = int(os.stat(file_path).st_size) file_f = open(file_path, "rb") block = file_f.read(1024) blockCounter = len(block) #same as prior while (block): calc = (float(blockCounter) / float(filesize)) * float(100) print calc hexblock = binascii.hexlify(block) block = rsa.encrypt_text(hexblock, FSPUBLIC) s.send(block) block = file_f.read(1024) blockCounter += len(block) file_f.close() s.close() # s.send(self.data) print "RSA FILETRANSFER COMPLETE" wx.CallAfter(self.text_send.AppendText, "\n" + t() + "RSA FILETRANSFER COMPLETE" + "\n") # terminate the thread def stop(self): print "Trying to stop thread " if self.process is not None: self.process.terminate() self.process = None
def run(self): print "size of public_key", len(str(self.public_key)) # create a new socket and Bind to a Random free port (0) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('localhost', 0)) #get the address and store so it can be returned newSocketAddress = s.getsockname() self.newReadSocketAddress = newSocketAddress import math suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] def human_size(nbytes): rank = int((math.log10(nbytes)) / 3) rank = min(rank, len(suffixes) - 1) human = nbytes / (1024.0**rank) f = ('%.2f' % human).rstrip('0').rstrip('.') return '%s %s' % (f, suffixes[rank]) # if the mode is AES if self.mode == 1: #Wait to accept one client s.listen(1) print "@@@@@@@@@@@@@@@@@@@@@@@@-SECOND SOCKET CREATED AES-@@@@@@@@@@@@@@@@@@@@@@" self.socket = s # accept the client as a new socket sock sock, addr = self.socket.accept() #receive the original file path, padded with white space t0 1024 characters self.original_file_path = sock.recv(1024) #strip the whitespace padding unpaddedOriginal = self.original_file_path.strip() print "unpaddedOriginal", unpaddedOriginal, len(unpaddedOriginal) #split the path and name, then rename with "_txCopy" path, filename_ext = os.path.split(unpaddedOriginal) filename, extension = os.path.splitext(filename_ext) filename = filename + "_txCopy" + extension file_f = open(filename, 'wb') #open in binary block = sock.recv(2752) blockCounter = len(block) while (block): print "RECIEVED", human_size(blockCounter) block = self.aes.dec_str(block) unhexblock = binascii.unhexlify(block) file_f.write(unhexblock) block = sock.recv(2752) blockCounter += len(block) wx.CallAfter(self.text_send.AppendText, "\n" + t() + "AES FILETRANSFER RECIEVED" + "\n") print "!!!!!!!!!!!!!!!!!! FILETRANSFER COMPLETED !!!!!!!!!!!!!!!!!!!!!!!!!!!!!" file_f.close() sock.close() print "@@@@@@@@@@@@@@@@@@@@@@@ new socket closed @@@@@@@@@@@@@@@@@@@@@@@@@@@@" # The same as above but with RSA if self.mode == 2: s.listen(1) print "@@@@@@@@@@@@@@@@@@@@@@@@-SECOND SOCKET CREATED RSA-@@@@@@@@@@@@@@@@@@@@@@" self.socket = s sock, addr = self.socket.accept() #Send This clients Public key to the calling client sock.send(self.public_key) rsa = RSAClass() #receive if this is private message mode private = sock.recv(1) if private == "1": print "ENTERING PRIAVTE MODE" privatemessage = sock.recv(2048) privatemessage = privatemessage.strip() privatemessage = rsa.decrypt_text(privatemessage, self.private_key) #append the private received message to the chat window wx.CallAfter( self.text_send.AppendText, "\n" + t() + "RSA_PRIVATE:" + privatemessage + "\n") else: self.original_file_path = sock.recv(1024) # print "self.original_file_path", self.original_file_path, len(self.original_file_path) unpaddedOriginal = self.original_file_path.strip() print "unpaddedOriginal", unpaddedOriginal, len( unpaddedOriginal) path, filename_ext = os.path.split(unpaddedOriginal) filename, extension = os.path.splitext(filename_ext) filename = filename + "_txCopy" + extension file_f = open(filename, 'wb') # data = sock.recv(1024) block = sock.recv(4608) #----receiving & decrypting------- blockCounter = len(block) while (block): print "RECIEVED ", human_size(blockCounter) block = rsa.decrypt_text(block, self.private_key) unhexblock = binascii.unhexlify(block) file_f.write(unhexblock) block = sock.recv(4608) blockCounter += len(block) wx.CallAfter(self.text_send.AppendText, "\n" + t() + "RSA FILETRANSFER RECIEVED" + "\n") print "!!!!!!!!!!!!!!!!!! FILETRANSFER COMPLETED !!!!!!!!!!!!!!!!!!!!!!!!!!!!!" file_f.close() sock.close() print "@@@@@@@@@@@@@@@@@@@@@@@ new socket closed @@@@@@@@@@@@@@@@@@@@@@@@@@@@"
class Client: """Class for a user of the chat client.""" def __init__(self): self.rsa = RSAClass() #generate the Public Private key pair for this client self.public_key, self.private_key = self.rsa.generate_keys() # read in the Public key of the Server from XML File self.pubKey = chilkat.CkPublicKey() self.pubKey.LoadXmlFile("Serverpublickey.xml") self.ServerPublicKey = self.pubKey.getXml() #objects for hashing and diffie hellman self.md5_crypt = chilkat.CkCrypt2() self.hashcrypt = chilkat.CkCrypt2() self.dhAlice = chilkat.CkDh() self.md5_crypt.put_EncodingMode("hex") # Set the hash algorithm: self.md5_crypt.put_HashAlgorithm("md5") self.hashcrypt.put_EncodingMode("hex") self.hashcrypt.put_HashAlgorithm("md5") # Unlock components above self.UnlockComponents() #create a oscket and connect to the server self.client = socket(AF_INET, SOCK_STREAM) self.client.connect(ADDR) # setup an AES object with cipher block chaining, 128-bit key, padding size and format self.a = AESClass("cbc",128,0,"hex") # source port of Client for use in communications later self.client_src_port = self.client.getsockname()[1] def UnlockComponents(self): success = self.md5_crypt.UnlockComponent("T12302015Crypt_sHyDCAFgIR1v") if (success != True): print(self.md4_crypt.lastErrorText()) sys.exit() success = self.hashcrypt.UnlockComponent("T12302015Crypt_sHyDCAFgIR1v") if (success != True): print(self.hashcrypt.lastErrorText()) sys.exit() success = self.dhAlice.UnlockComponent("T12302015Diffie_eegQ20BTIR5q") if (success != True): print(self.dhAlice.lastErrorText()) sys.exit() def setUpClient(self): #random nonce generated for the cient # seeded (probally with system time) to ensure new nonce generation # well as much as pseudorandom can ensure random.seed() nonce = random.randrange(10000000000000,99999999999999) # generate an ID dictionary for the client, passing its # public-key and nonce to the server # serializing the object # hashing it + concatenating the hash to ther serialized data # then encypting with the servers public to ensure the nonce # cannot be intercepted # send to server firstID = {'nonce' : nonce, 'public_key': self.public_key} pid = pickle.dumps(firstID) hashStr = self.md5_crypt.hashStringENC(str(nonce)) finalID = pid + hashStr encyptedpayload = self.rsa.encrypt_text(finalID, self.ServerPublicKey) self.client.send(encyptedpayload) # recieve the Responce from the server with orginal client nonce # and the servers nonce challange_Resp = self.client.recv(1024) # decypt with the clients public key challange_Resp = self.rsa.decrypt_text(challange_Resp,self.private_key) # decypt with the servers private - verifys - because nonces will be mangled # if there a different private RSA used - It is assumed server only has this key challange_Resp = self.rsa.decrypt_with_public(challange_Resp, self.ServerPublicKey) # remove the Hash of the orginal serialized object - 32 Characters from end of message h = challange_Resp[-32:] # remove the serialized object - to the last 32 characters of the data challange_Resp = challange_Resp[:-32] # rehash this object h2 = self.md5_crypt.hashStringENC(challange_Resp) # de-serialized the object back to a python dictionary challange_Resp = pickle.loads(challange_Resp) # extract the returned nonce-1, check if valid, close socket and exit if not nonce_1 = challange_Resp["cnonce"] if h == h2 and nonce == nonce_1: print "\n$$$$$$$$$$$$$$$$$$$$$$$$$$$$" print "Challange Integrity Verified" print "$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n" else: print "Integrity Challange Failed - closing connection" client.close() sys.exit(0) # extract the server nonce snonce = challange_Resp["snonce"] #check to see if a "Master Client" has setup the CHatroom #if not then initate the Diffie-Hellman Key exchange with the server # if it has happened retieve the Session-key from the server # have to have exact bytes(sync issues) !!!!!!!!!!!!!!!!!!!! inital_setup = self.client.recv(1) print "inital_setup has occured before = ", inital_setup serverKey = None if inital_setup == "1": print "attempt to recv server key" serverKey = self.client.recv(1280) serverKey = self.rsa.decrypt_text(serverKey, self.private_key) serverKey = self.rsa.decrypt_with_public(serverKey, self.ServerPublicKey) h = serverKey[-32:] serverKey = serverKey[:-32] h2 = self.md5_crypt.hashStringENC(serverKey) serverKey = pickle.loads(serverKey) if h == h2 and serverKey["cnonce"] == nonce and serverKey["snonce"] == snonce: sk = serverKey["aes_key"] print "serverSessionKey", sk print "setting serverSessionKey" self.a.set_sessionkey(sk) iv = self.a.getCrypt().hashStringENC(sk) self.a.setIv(iv) else: print "Integrity Mismatch" client.close() sys.exit(0) # Recieved "Pickled" object on socket - ie serialised to String # Deserialize Data recieved back into # Python dictionary then remove the objects else: try: pk1 = self.client.recv(1792) pk2 = self.client.recv(1792) pk1 = self.rsa.decrypt_text(pk1, self.private_key) pk2 = self.rsa.decrypt_text(pk2, self.private_key) defragment = pk2 + pk1 defragment = self.rsa.decrypt_with_public(defragment, self.ServerPublicKey) h = defragment[-32:] defragment = defragment[:-32] h2 = self.md5_crypt.hashStringENC(defragment) dictObj = pickle.loads(defragment) if h == h2 and dictObj["cnonce"] == nonce and dictObj["snonce"] == snonce: p = dictObj["p"] g = dictObj["g"] g = int(g) eBob = dictObj["e"] else: print "Integrity Mismatch" client.close() sys.exit(0) except: print "fails to recieve Diffie-hellman data" sys.exit(0) # use the information for Diffie-hellman cleint side success = self.dhAlice.SetPG(p,g) if (success != True): print("P is not a safe prime") sys.exit() eAlice = self.dhAlice.createE(256) eAlice = self.rsa.encrypt_text(eAlice, self.ServerPublicKey) print "size of eAlice", len(str(eAlice)) self.client.send(eAlice) #Alice's shared secret kAlice = self.dhAlice.findK(eBob) print("Alice's shared secret (should be equal to Bob's)") print(kAlice) sessionkey = self.hashcrypt.hashStringENC(kAlice) print "SessionKey", sessionkey self.a.set_sessionkey(sessionkey) iv = self.a.getCrypt().hashStringENC(sessionkey) self.a.setIv(iv) # print "serverKey testing" # print type(serverKey) # print len(str(serverKey)) # depending on if this is a first setup or not # use the key (ie same key)for AES ---- one that is sent in open # would have to use a digital envelope of the like to achieve this properly # setup this sides AES object self.a.setupAES() print "-------------AES KEY-----------------" print self.a.get_key()
class Chatroom(asyncore.dispatcher): #asyncore dispatcher listening on local-host random socket def __init__(self, address=('localhost', 0)): asyncore.dispatcher.__init__(self) #import the Servers Keys, Saved to XML in FileSystem privkey = chilkat.CkPrivateKey() privkey.LoadXmlFile("Serverprivatekey.xml") self.ServerPrivateKey = privkey.getXml() #create RSA object self.rsa = RSAClass() #Chilkat object forCreating hashes self.hashcrypt = chilkat.CkCrypt2() success = self.hashcrypt.UnlockComponent("T12302015Crypt_sHyDCAFgIR1v") if (success != True): print(hself.ashcrypt.lastErrorText()) sys.exit() # setting encoding mode for hashing algorithm self.hashcrypt.put_EncodingMode("hex") self.hashcrypt.put_HashAlgorithm("md5") # setup data for Diffie Hellman Key exchange self.dhBob = chilkat.CkDh() success = self.dhBob.UnlockComponent("T12302015Diffie_eegQ20BTIR5q") if (success != True): print(self.dhBob.lastErrorText()) sys.exit() self.dhBob.UseKnownPrime(2) self.p = self.dhBob.p() self.g = self.dhBob.get_G() self.eBob = self.dhBob.createE(256) #initially set the the AES object with cipher block chaining 128bit self.aesObj = AESClass("cbc",128,0,"hex") self.inital_setup = "0" #store client IDS and nonces # nonces used in replay protection self.CLIENT_ID_STORE ={} self.CLIENT_ID = [] #placeholders fo the keys (session and shared the same really) self.sharedKey = None self.sessionkey = None # self.set_reuse_addr() #bind to socket and listen self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.bind(address) #print ("Address Server", address) # accept with no backlog # syncore dispatcher handles it all self.listen(1) #store connected clients in LIST self.remote_clients = [] #Authentication Protocol Steps occur here #Diffy Hellman, key exchange #digital signing of messages #hashes included in messages #confidential provided by the clients public key that was #transmitted to the server on its initial connection in the accept handler #when the challenge response occurred #the nonces, socket, keys, source address and public keys are passed to this method def auth(self, client, address, cpub, snonce, cnonce): #send if this setup has happened already with an initial client #because the session key was already generated #doing otherwise would create different keys! #send the flag to the connected client #so they can comply with protocol client.send(self.inital_setup) #if this has already happened then send the client # the symmetric key in a digital envelope using the Public key they submitted if self.inital_setup == "1": print 'Setup for new client', address print ">>>>>>>>>>>>>>>>>>>>>>>Sending Session Key>>>>>>>>>>>>>>>>>" print ">>>>>>>>>>>>>>>>>>>>>>>Digital Envelope>>>>>>>>>>>>>>>>>>>>>\n" #create a dictionary of data dictobj = {'aes_key':self.aesObj.get_key(),"snonce":snonce, "cnonce":cnonce} #serialize it pickledump = pickle.dumps(dictobj) #!!!!!HASH!!!!! it h = self.hashcrypt.hashStringENC(pickledump) #concatenate the hash to the serialized data pickledump = pickledump + h #encrypt with the server !!!!!PRIVATE KEY!! for !!!!DIGTIAL SIGNATURE!! sk = self.rsa.encrypt_with_private(pickledump, self.ServerPrivateKey) #encrypt with the clients Public key for !!!!!!CONFIDENTIALITY!!!!!!!! sk = self.rsa.encrypt_text(sk, cpub) # send it back to the client client.send(sk) else: print 'Setup for first client', address # serialize objects with dictionary and "pickle" #these are the data requirement for the client to complete the # !!!!!-----diffie hellman-----!!!! mathematical process dictobj = {'p' : self.p, 'g' : self.g,"e" : self.eBob, "snonce":snonce, "cnonce":cnonce} pickdump = pickle.dumps(dictobj) #hash serialized data, concatenate and encrypt with the Private key Server for #!!!!!Digital Signature!!!! h = self.hashcrypt.hashStringENC(pickdump) pickdump = pickdump + h pickdump = self.rsa.encrypt_with_private(pickdump, self.ServerPrivateKey) #Have the split the data and encypt each half separately with the #clients public key # Data was exceeding the MODULUS Size used for the RSA Object pk1 = self.rsa.encrypt_text(pickdump[-768:], cpub) pk2 = self.rsa.encrypt_text(pickdump[:-768], cpub) #Send the FRAGMENTED packet to the client for reassembly client.send(pk1) client.send(pk2) ## without this loop will get a resource unavailable # error crashing the server ---- wait till receive loop = True while loop: try: #receive the clients "shared value", generated for the Public #Diffie Hellman components sent to from the server eAlice = client.recv(768) try: #decrypt the message with the servers Private key #Confidentiality #(unnecessary!!!!!!!! as this is public data --- but added anyway) eAlice = self.rsa.decrypt_text(eAlice, self.ServerPrivateKey) except: "nothinf" loop = False except: "do nothing" # using the information from Client kBob = self.dhBob.findK(eAlice) #generate the MUTUALLY GENERATED SHARED SECRET self.sharedKey = kBob print "Shared Secret information" print(address, "shared secret (should be equal to Bob's)") print self.sharedKey # Use a hashing algorithm to generate 128 bit Session key self.sessionkey = self.hashcrypt.hashStringENC(kBob) print "" #Console Outputs (testing) print "-----------Session-key---------------" print "------------generated---------------" print self.sessionkey print "-----------------------------------" # Use custom AES object # if the setup hes not happen already then # use the current new session key # and setup the AES object if self.inital_setup == "0": # iv is MD5 hash of session key iv = self.aesObj.getCrypt().hashStringENC(self.sessionkey) self.aesObj.setIv(iv) self.aesObj.set_sessionkey(self.sessionkey) self.aesObj.setupAES() # first time setup has occurred self.inital_setup = "1" return True # socket accept event handler of Asyncore dispatcher # used to accept new Clients connections in a Synchronous manner then after # challenge response and protocol wrap them in a approximation of Asynchronous behavior # with Asyncore Dispatcher which will poll each at timed intervals def handle_accept(self): # Accept event handler on listening socket # Accept a new client then start the Protocol Process socket, addr = self.accept() if (socket == None): return print 'Accepted client from port ', addr sleep(0.1) # remove the client identifier ID = socket.recv(1024) #decrypt with the server Private-key client_ID = self.rsa.decrypt_text(ID, self.ServerPrivateKey) #extract and generate hash orginal_hash = client_ID[-32:] #de-concatenate the clients ID client_ID = client_ID[:-32] print "***********************" print "***********************" dictObj = pickle.loads(client_ID) # clients nonce value cnonce = dictObj["nonce"] #Generate a comparison HASH value testhash = self.hashcrypt.hashStringENC(str(cnonce)) ###Should disconnect them here if this Check fails if orginal_hash == testhash: print "\nNONCE Integrity Validated\n" # extract the Clients RSA public key cpub = dictObj["public_key"] #store their nonce self.CLIENT_ID_STORE[addr] = cnonce #SERVER generate a random nonce random.seed() snonce = random.randrange(10000000000000,99999999999999) #response the the client with clients nonce and Servers nonce responce = {"snonce":snonce, "cnonce": cnonce} #serialize the dictionary responce = pickle.dumps(responce) #hash it for INTEGRITY h = self.hashcrypt.hashStringENC(str(responce)) #concatenate the hash to serialized data responce = responce + h # encrypt with the Servers Private key for DIGITAL SIGNATURE responce = self.rsa.encrypt_with_private(responce, self.ServerPrivateKey) # Encrypt with the clients public key for Confidentiality responce = self.rsa.encrypt_text(responce, cpub) #send message socket.send(responce) #Replay Protection (If a client nonce has occurred Before then dont add them # to the Ayncore Wrapper Chat Room) # This would have to be save to a local Database to be really useful # as all nonces as lost once the server is down allowed = True if self.inital_setup == "1": print "previous nonces" for c in list(self.CLIENT_ID): print c[1] if c[1] == cnonce and snonce == c[2]: print "AUTH already occurred for ", c[0] #set allowed to false #they wont get added to the system allowed = False if allowed == True: client_id_list =[ (cpub), (cnonce), (snonce)] self.CLIENT_ID.append(client_id_list) # If setup protocol returns true # add remote socket to room stat = self.auth(socket, addr, cpub, snonce, cnonce) if stat == True: self.remote_clients.append(RemoteClient(self, socket, addr)) #Handle Read #Called when the asynchronous loop detects that a read #call on the channels socket will succeed. def handle_read(self): self.read() def broadcast(self, message): # broadcasts messages to all sockets that are connected # to the server - stored in (remote_clients) # filterS the origin socket of the message (does not return the message) try: orginal_hash = message[-32:] # remove the original serialized object from the concatenated # hash message = message[:-32] #hash the extracted object test_hash = self.hashcrypt.hashStringENC(message) # de-serialize and extract data dictObj = pickle.loads(message) #get the source port of the message src_port = dictObj["src_port"] #data src_data = dictObj["data"] #is this RSA or AES (only used in the PEER TO PEER message exchange) mode = dictObj["FTX_ENC"] # IF a <list> command (message) is sent then # send back a string of connected ports remoteConnectedClients = [] if dictObj["list"] == True: connlist = "Conn_list " for remote_client in self.remote_clients: if remote_client.get_address()[1] == src_port: # ID this port as coming from the client that requested this LIST connlist = connlist + " : " + str(remote_client.get_address()[1]) + " <-You " else: remoteConnectedClients.append(remote_client.get_address()[1]) connlist = connlist + " : " + str(remote_client.get_address()[1]) connlist = self.aesObj.enc_str(connlist) connlist = {"data" : connlist, "src_port": src_port, "FTX_ENC": mode, "remoteConnectedClients": remoteConnectedClients} connlist = pickle.dumps(connlist) packet = {"data" : src_data, "src_port": src_port, "FTX_ENC": mode, "remoteConnectedClients": None} src_data = pickle.dumps(packet) # Check the Integrity of received data vrs the new hash of extracted obj # NOT OVERLY USEFUL WITH STRING MESSAGES if test_hash == orginal_hash: "Integrity Verified" else: print "Integrity fail" # test Decryption --- (not necessary) test = pickle.loads(src_data) dec_message_test = self.aesObj.dec_str(test["data"]) print "Test Decrypt :", dec_message_test #console message print "Broadcasting encrypted mess :", test["data"] , " from 127.0.0.1:", src_port #loop through all the connected clients for remote_client in self.remote_clients: # don't broadcast the message back to source socket if not (remote_client.get_address()[1] == src_port) and (dictObj["tx"] == False): remote_client.send(src_data) # send back the LIST data to who requested it (connection list) if remote_client.get_address()[1] == src_port and dictObj["list"] == True: remote_client.send(connlist) #START A PEER TO PEER FILE TRANSFER HANDSHAKE with a Destination Port #Choose by the source client #this will create 2 new THREADS , with new SOCKETS, to send encrypted files and strings #directly from client to client by passing the server if remote_client.get_address()[1] == int(dictObj["p2p_port"]) and dictObj["tx"] == True: remote_client.send(src_data) except Exception, e: print "er Broadcasting" print str(e)