class Node: def __init__(self, node_id): self.node_id = node_id self.authorised_users = [] self.transaction_history = [] # Set up crypto self.diffie = DiffieHellman() self.exchange_keys() self.sync() print("Node Established.") def sync(self): conn = socket.socket() conn.connect((SERVER_IP, SERVER_PORT)) conn.send(self.crypt(b"SYNC")) def update_authorised_users(self): pass def send_transactions(self): pass def main_loop(self): pass def exchange_keys(self): self.diffie.generate_public_key() conn = socket.socket() conn.connect((SERVER_IP, SERVER_PORT)) conn.send(self.crypt(self.node_id.zfill(8).encode())) conn.send(b"KEYX") key_len = str(len(str(self.diffie.public_key))).zfill(4).encode() conn.send(key_len) conn.send(str(self.diffie.public_key).encode()) server_key_len = int(conn.recv(4)) server_key = int(conn.recv(server_key_len)) self.diffie.generate_shared_secret(server_key) conn.close() def crypt(self, text): key = self.diffie.shared_key if type(text) == str: text = text.encode() if type(key) == str: key = key.encode() assert type(text) == type(key) == bytes output_values = [] for i, b in enumerate(text): output_values.append(b ^ key[i % len(key)]) return bytes(output_values)
class MessangerClient(asyncore.dispatcher): def __init__(self, host, port, login, password): asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect((host, port)) self.login = login self.password = password self.Key = DiffieHellman() self.Key.generate_public_key() self.buffer = json.dumps({'action': 'handshake', 'data': {'pubkey': int_to_base_str(self.Key.public_key)}}).encode() self.cipher = None def handle_connect(self): pass def handle_close(self): self.close() def handle_read(self): data = self.recv(4024).decode('utf-8') if data: if self.cipher is not None: j = json.loads(self.cipher.decrypt(data)) else: j = json.loads(data) print(j) if j["action"] == "handshake": tmp = base_str_to_int(j["data"]["pubkey"]) h = SHA.new(j["data"]["pubkey"].encode()).digest() self.Key.generate_shared_secret(tmp) SignR = int(j["data"]["SignR"]) SignS = int(j["data"]["SignS"]) if not ElGamalKey.verify(h, (SignR, SignS)): raise("BAD SIGNATURE") self.cipher = AESCipher(str(self.Key.shared_key).encode()) self.buffer = json.dumps({'action': 'auth', 'data': {'login': login, 'pass': password}}).encode('utf-8') def writable(self): return len(self.buffer) > 0 def handle_write(self): if self.cipher is not None: sent = self.send(self.cipher.encrypt(self.buffer.decode())) self.buffer = self.buffer[sent:] else: sent = self.send(self.buffer) self.buffer = self.buffer[sent:]
def main(): """Main loop See vpn.md for details """ # Create the socket server_sckt = socket(AF_INET, SOCK_STREAM) server_sckt.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) server_sckt.bind((HOST, PORT)) server_sckt.listen() print(f"Listening on {HOST}:{PORT}") conn, client = server_sckt.accept() print(f"New client: {client[0]}:{client[1]}") # Negotiating the cipher print("Negotiating the cipher") msg_in = conn.recv(4096).decode('utf-8') proposed = parse_proposal(msg_in) cipher_name, key_size = select_cipher(SUPPORTED_CIPHERS, proposed) print(f"We are going to use {cipher_name}{key_size}") msg_out = generate_cipher_response(cipher_name, key_size) conn.send(msg_out.encode()) # Negotiating the key print("Negotiating the key") dh = DiffieHellman() dh.generate_public_key() msg_in = conn.recv(4096).decode('utf-8') client_public_key = parse_dhm_request(msg_in) dh.generate_shared_secret(client_public_key) msg_out = generate_dhm_response(dh.public_key) conn.send(msg_out.encode()) cipher, key, iv = get_key_and_iv(dh.shared_key, cipher_name, key_size) print("The key has been established") print("Initializing cryptosystem") crypto = cipher.new(key, cipher.MODE_CBC, iv) hashing = HMAC.new(key, digestmod=SHA256) print("All systems ready") while True: msg_in = conn.recv(4096) if len(msg_in) < 1: conn.close() break msg, hmac = read_message(msg_in, crypto) validate_hmac(msg_in, hmac, hashing) print(f"Received: {msg}") msg_out = f"Server says: {msg[::-1]}" conn.send(msg_out.encode())
class client: def __init__(self,socet,ip_port,s): self.alice = DiffieHellman() self.key = None self.socet = socet self.ip = ip_port[0] self.port = ip_port[1] self.alice.generate_public_key() #self.ip = ip def df(self): m_df = {["alice":self.alice.public_key]} self.socet.send(json.dumps(m_df)) data = self.socet.recv(json.dumps(m_df)) if data:
def main(): """Main event loop See vpn.md for details """ # Start the server client_sckt = socket(AF_INET, SOCK_STREAM) client_sckt.connect((HOST, PORT)) print(f"Connected to {HOST}:{PORT}") # Negotiating the cipher print("Negotiating the cipher") # Send proposal to the server msg_out = generate_cipher_proposal(SUPPORTED_CIPHERS) client_sckt.send(msg_out.encode()) msg_in = client_sckt.recv(4096).decode('utf-8') cipher_name, key_size = parse_cipher_selection(msg_in) print(f"We are going to use {cipher_name}{key_size}") # Negotiating the key print("Negotiating the key") dh = DiffieHellman() dh.generate_public_key() msg_out = generate_dhm_request(dh.public_key) client_sckt.send(msg_out.encode()) msg_in = client_sckt.recv(4096).decode('utf-8') server_public_key = parse_dhm_response(msg_in) dh.generate_shared_secret(server_public_key) cipher, key, iv = get_key_and_iv(dh.shared_key, cipher_name, key_size) print("The key has been established") # Initialize Cryptosystem print("Initializing cryptosystem") crypto = cipher.new(key, cipher.MODE_CBC, iv) hashing = HMAC.new(key, digestmod=SHA256) print("All systems ready") while True: msg = input("Enter message: ") if msg == "\\quit": client_sckt.close() break ciph_out, hmac_out = encrypt_message(msg, crypto, hashing) client_sckt.send(ciph_out + hmac_out.encode()) msg_in = client_sckt.recv(4096) print(msg_in.decode("utf-8"))
def key_exchange(self, conn, addr): diffie = DiffieHellman() diffie.generate_public_key() public_key = diffie.public_key key_to_send = str(public_key).encode() key_len = str(len(key_to_send)).zfill(4).encode() client_key_len = int(conn.recv(4)) client_key = int(conn.recv(client_key_len)) conn.send(key_len) conn.send(key_to_send) diffie.generate_shared_secret(client_key) client_id = crypt(conn.recv(8), diffie.shared_key).decode() conn.close() self.store_node(client_id, addr, diffie.shared_key)
def session(self): alice = DiffieHellman(group=5, key_length=200) alice.generate_public_key() self.Message_send.message = str(alice.public_key) # send puzzle answer and ga mod p self.send_message() # receive the session key of server self.receive_message() alice.generate_shared_secret(int(self.Message_rec.gb_mod_p)) # set up the session key Kas self.Kas = str(alice.shared_secret)[:16].encode() self.iv = self.Message_rec.iv # print("Shared secret is:", int.from_bytes(self.Kas, sys.byteorder)) # Decryption plain_text = self.decryption_with_timestamp() # Verify signature correct_message = str( alice.public_key) + "|" + self.Message_rec.gb_mod_p correct_message = correct_message.encode() ## load public key with open("public_key.der", "rb") as key_file: public_key = serialization.load_der_public_key( key_file.read(), backend=default_backend()) ## verify the signature try: public_key.verify( plain_text, correct_message, paddings.PSS(mgf=paddings.MGF1(hashes.SHA256()), salt_length=paddings.PSS.MAX_LENGTH), hashes.SHA256()) # print("Signature verify success!") except: print('Error in verifying the signature!') sys.exit(1)
def _createAndSaveKeyHandler(self): keyHandler = DiffieHellman(key_length=200, group=5) keyHandler.generate_public_key() self._insertKeyHandlerIntoDb(keyHandler) return keyHandler
class Client: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mujAES = None cli = None cislo = 0 def __init__(self, adress): self.sock.connect((adress, 9876)) if os.path.isfile('User.private.pem') == False or os.path.isfile( 'client1.cert.pem') == False: createCSR('User', 'heslo', {'CN': 'USER_FQDN'}) self.poslatCertReq() print("ZADAM SI CERTIFIKAT") else: print("NACITAM ZE SLOZKY JAK BOSSs") self.cert = OpenSSL.crypto.load_certificate( crypto.FILETYPE_PEM, open('client1.cert.pem').read()) self.poslatCert() self.cli = DiffieHellman() self.cli.generate_public_key() #presunout do runu self.vyzadatKlic() iThread = threading.Thread(target=self.sendMessage) iThread.daemon = True iThread.start() self.run() def run(self): while True: data = self.sock.recv(BUFSIZE) #misto na hrani si s daty if not data: #ukonceni komunikace break elif data[0:1] == b"\x66": with open('client1.cert.pem', 'wb') as cert: cert.write(data[1:]) self.nastavitCert(data[1:]) #self.cert=OpenSSL.crypto.load_certificate(crypto.FILETYPE_PEM,data[1:]) elif data[0:1] == b"\x11": #kdyz prijde ridici znak x11-posleme na vyzadani klic self.poslatKlic() elif data[0:1] == b"\x98": createCSR('User', 'heslo', {'CN': 'USER_FQDN'}) self.poslatCertReq() elif data[0:1] == b"\x12": #kdyz prijde ridici znak x12 tak si nastavime klic ktery nasleduje po tomto bytu self.nastavitKlic(data[1:]) elif data[0:1] == b"\x13": #nezasifrovana komunikace print(data.decode()) #vynuceni DH pokud prijde nezasifrovana zprava #self.sock.send(b'\x11') elif data[0:1] == b"\x14": #nastaveni klice v pripade ze byl vyzadan nebo tak neco self.jinenastaveniklice(data[1:]) elif data[0:1] == b'\x20': self.nastavitCert(data[1:]) else: #vychozi stav- prijdou data bez ridiciho znaku-> predpokladame ze jsou zasifrovana AESem podle dohodnuteho hesla data = self.mujAES.decrypt(data) try: print("client " + str(self.cislo) + ":" + data.decode()) except: continue def vyzadatCert(self): self.sock.send(b'\x65') def nastavitCert(self, data): #self.cert=OpenSSL.crypto.load_certificate_request(crypto.FILETYPE_PEM, data) self.cert = OpenSSL.crypto.load_certificate(crypto.FILETYPE_PEM, data) def poslatCert(self): text = OpenSSL.crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert) self.sock.send(b'\x33' + text) def poslatCertReq(self): #posle certifikat na podepsani¨ with open('User.CSR.pem') as cert: certificate = OpenSSL.crypto.load_certificate_request( crypto.FILETYPE_PEM, cert.read()) certext = OpenSSL.crypto.dump_certificate_request( crypto.FILETYPE_PEM, certificate) print(certext) self.sock.send(b'\x15' + certext) def poslatKlic(self): #posle ridici znak nasledovany klicem self.sock.send(b'\x12' + str(self.cli.public_key).encode()) def jinenastaveniklice(self, data): #dela zajimave veci, ale jen v urcitem pripade self.cli.generate_shared_secret(int(data.decode()), echo_return_key=True) superklic = str(self.cli.shared_secret) xy = hashlib.sha256(superklic.encode()).hexdigest()[:32] print("2222222222222222222222222222") self.cislo = 2 print(xy) self.mujAES = Encryptor.Encryptor(xy) def nastavitKlic(self, data): #nastavuje klic na zaklade dat ktere dostane self.cli.generate_shared_secret(int(data.decode()), echo_return_key=True) superklic = str(self.cli.shared_secret) xy = hashlib.sha256(superklic.encode()).hexdigest()[:32] print("111111111111111111111") self.cislo = 1 print(xy) self.mujAES = Encryptor.Encryptor(xy) self.sock.send(b'\x14' + str(self.cli.public_key).encode()) def vyzadatKlic(self): #nemam klic ale chci, poslu ridici znak self.sock.send(b'\x11') def sendMessage(self): #hlavni chatova smycka while True: msg = str(input("")) if self.mujAES is not None: msg = self.mujAES.encrypt(msg.encode()) self.sock.send(msg) else: msg = msg.encode() self.sock.send(b'\x13' + msg)
class MessageHandler(asyncore.dispatcher_with_send): def __init__(self, sock): asyncore.dispatcher_with_send.__init__(self, sock) self.name = 0 self.Key = DiffieHellman() self.Key.generate_public_key() self.cipher = None def handle_read(self): data = self.recv(4096).decode() print("data: ", data) if data: if self.cipher is not None: j = json.loads(self.cipher.decrypt(data)) else: j = json.loads(data) print("loginfo: " + json.dumps(j)) if j["action"] == "register" and self.cipher: try: if not j["data"]["login"] in users.keys(): users[j["data"]["login"]] = j["data"]["pass"] self.name = j["data"]["login"] clients[self.name] = self self.send(self.cipher.encrypt(json.dumps({"action": "register", "status": "AUTH_OK"}))) else: self.send(self.cipher.encrypt(json.dumps({"action": "register", "status": "AUTH_ERR"}))) self.close() except Exception: self.send(self.cipher.encrypt(json.dumps({"action": "register", "status": "AUTH_ERR"}))) self.close() elif j["action"] == "auth" and self.cipher: try: if users[j["data"]["login"]] == j["data"]["pass"]: self.name = j["data"]["login"] clients[self.name] = self self.send(self.cipher.encrypt(json.dumps({"action": "auth", "status": "AUTH_OK"}))) else: self.send(self.cipher.encrypt(json.dumps({"action": "auth", "status": "AUTH_ERR"}))) self.close() except Exception: self.send(self.cipher.encrypt(json.dumps({"action": "auth", "status": "AUTH_ERR"}))) self.close() elif j["action"] == "test": s = j["data"].encode() print(s) elif j["action"] == "message" and self.cipher: try: chel = clients[j["data"]["to"]] chel.send(chel.cipher.encrypt(json.dumps({"action": "message", "data": {"from": self.name, "message": j["data"]["message"]}}))) except Exception: self.send(self.cipher.encrypt(json.dumps({"action": "message", "status": "MESSAGE_ERR"}))) elif j["action"] == "handshake": try: h = SHA.new(int_to_base_str(self.Key.public_key).encode()).digest() while 1: k = random.StrongRandom().randint(1, ElGamalObjKey.p-1) if GCD(k, ElGamalObjKey.p-1) == 1: break (SignR, SignS) = ElGamalObjKey.sign(h, k) self.send(json.dumps({"action": "handshake", "status": "HANDSHAKE_OK", "data": {"pubkey": int_to_base_str(self.Key.public_key), "SignR": SignR, "SignS": SignS}}).encode()) print("pubkey: " + str(base_str_to_int(j["data"]["pubkey"]))) self.Key.generate_shared_secret(base_str_to_int(j["data"]["pubkey"])) self.cipher = AESCipher(str(self.Key.shared_key).encode()) except Exception as e: print("ERROR: ", e) self.send(json.dumps({"action": "handshake", "status": "HANDSHAKE_ERR"}).encode()) else: print("WATAFA")
def requestHandler(conn, addr): ''' This method handles a new download request ''' # First generate a public-private key pair dh = DiffieHellman() dh.generate_public_key() publicKey = dh.public_key # Next, send the public key using KEY_EXCHANGE. The segment size is 2479. conn.sendall(('KEY_EXCHANGE\n' + str(publicKey)).encode('utf-8', errors='ignore')) # Receive a similar segment from client. This segment contains the client's public key. data = receiveData(conn, 2479) messageType = data.decode('utf-8', errors='ignore').split('\n')[0] if messageType != 'KEY_EXCHANGE': print("The client sent an illegal response. Closing connection..") conn.close() return clientPublicKey = int(data.decode('utf-8', errors='ignore').split('\n')[1]) sharedKey = '' # Generate the shared key using Diffie Hellman algorithm and the public key of client and server try: dh.generate_shared_secret(clientPublicKey) sharedKey = bytes.fromhex(dh.shared_key) except Exception as e: print("The client sent an illegal response. Closing connection..") conn.close() return print('Key exchange successful: ' + dh.shared_key) print('Generating Ciphers..') # Generate a cipher which will use the shared key to encrypt all outgoing data cipher = AES.new(sharedKey, AES.MODE_CBC, 'jdirlfhixhtkwlif'.encode('utf-8')) print('Encrypting File list..') # Encrypt the file list with the cipher sharedFilesList = [] for i in sharedFiles: sharedFilesList.append(i) fileList = ('\n'.join(sharedFilesList)).encode('utf-8') encryptedFileList = cipher.encrypt(pad(fileList, AES.block_size)) requiredSize = len(encryptedFileList) # Send the file list size. We use FILELIST to send the file list size print('Sending File List..') conn.sendall( ('FILELIST\n' + padInteger(requiredSize, 20)).encode('utf-8', errors='ignore')) # Wait till the server doesn't receive READY signal indicating that the client is ready to take the data data = receiveData(conn, 5).decode('utf-8', errors='ignore') if data != 'READY': print('Client is not ready to receive file list..') conn.close() return # Send the encrypted file list now. The segments contain only body and no header conn.sendall(encryptedFileList) # Wait for acknowloedgement data = receiveData(conn, 3).decode('utf-8', errors='ignore') if data == 'ACK': print('File list was received successfully by client..') else: print('No Acknowledgement received..') conn.close() return # Wait for a file request print('Waiting for request..') data = receiveData(conn, 28).decode('utf-8', errors='ignore').split('\n') idx = int(data[1]) if data[0] != 'REQUEST': print('The client sent an illegal response. Closing connection..') conn.close() else: if idx < 0 or idx >= len(sharedFilesList): print( '\n\nThe client sent an illegal response. Closing connection..' ) conn.close() return else: # Open the requested file. Encrypt it with the cipher and send it. fileName = sharedFilesList[idx].split('/') fileName = fileName[len(fileName) - 1] file = open(sharedFilesList[idx], 'rb') unencryptedData = file.read() file.close() cipher = AES.new(sharedKey, AES.MODE_CBC, 'jdirlfhixhtkwlif'.encode('utf-8')) encryptedData = cipher.encrypt(pad(unencryptedData, AES.block_size)) requiredPackets = len(encryptedData) # Send the file size. We use FILE to send the file size conn.sendall(('FILE\n' + padInteger(requiredPackets, 20)).encode( 'utf-8', errors='ignore')) # Wait for the ready signal data = receiveData(conn, 5).decode('utf-8', errors='ignore') if data != 'READY': print('Client is not ready to receive the file..') conn.close() return print("Sending the file '" + fileName + "'.") # Sent the encrypted file conn.sendall(encryptedData) print("Sent! Awaiting Acknowledgement..") # Wait for acknowledgement data = receiveData(conn, 3).decode('utf-8', errors='ignore') if data == 'ACK': print('Client received the file successfully') conn.close() else: print('An unknown error occured in file transfer') conn.close()
class Client: def __init__(self, node_table): self.next_node = "" self.id = "client" self.node_table = node_table self.send_ops = { OP.CREATE: self.get_create_packet, OP.EXTEND: self.get_extend_packet } self.setup_keys() self.connect_to_signals() def setup_keys(self): self.aes_keys = {} self.dhke = DiffieHellman() self.dhke.generate_public_key() self.dh_pub = str(self.dhke.public_key).encode('utf8') self.__dh_sharedkey = None def connect_to_signals(self): dispatcher.connect(self.handle_created, signal=OP.CREATED, sender=dispatcher.Any) dispatcher.connect(self.handle_extended, signal=OP.EXTENDED, sender=dispatcher.Any) dispatcher.connect(self.handle_extended, signal=OP.EXTEND, sender=dispatcher.Any) def get_create_packet(self, receivers): iniciopKp=time.time() receiver = self.node_table[receivers[0]] msg = self.dh_pub enc_msg = rsa.encrypt(msg, receiver.pubkey) packet = Packet(src_id="client", op=OP.CREATE, dest=receiver.id, payload=(enc_msg, None)) print("client: Sending CREATE packet to {}".format(receiver)) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') return packet def send_message(self, receivers, op): iniciopKp=time.time() receivers = receivers.split() self.next_node = receivers[len(receivers) - 1] packet = self.send_ops[op](receivers) dispatcher.send(signal=op, sender=self, packet=packet) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') def handle_created(self, packet): if packet.dest != self.id: return iniciopKp=time.time() print("client: Handling CREATED packet from {}".format(packet.src)) (other_key, key_hash) = packet.msg # Generate the shared key self.dhke.generate_shared_secret(other_key) shared = self.dhke.shared_key m_key_hash = hashlib.sha1(str(shared).encode("utf-8")).hexdigest() if m_key_hash == key_hash: print("{}: DH Hash Comparison from {} SUCCESS".format(self.id, packet.src)) self.__dh_sharedkey = shared self.aes_keys[packet.src] = shared print("client: Entry node is now set to: ", self.next_node) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') return print("{}: DH Hash Comparison from {} FAIL".format(self.id, packet.src)) def handle_extended(self, packet): if packet.dest != self.id: return iniciopKp=time.time() print("client: Handling CREATED packet from {}".format(packet.src)) if not packet.decrypt_aes(self.aes_keys[packet.src]): print("{}: Decryption of EXTENDED packet from {} FAIL".format(self.id, packet.src)) return print("{}: Decryption of EXTENDED packet from {} SUCCESS".format(self.id, packet.src)) (other_key, key_hash) = tuple(packet.msg.split('|||')) other_key = int(other_key) key_hash = key_hash.strip() self.dhke.generate_shared_secret(other_key) shared = self.dhke.shared_key m_key_hash = hashlib.sha1(str(shared).encode("utf-8")).hexdigest() if m_key_hash == key_hash: # Only go through if hash matches print("{}: DH Hash Comparison from {} SUCCESS".format(self.id, packet.src)) self.__dh_sharedkey = shared self.aes_keys[packet.src] = shared print("client: Connection established with {}".format(self.next_node)) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') return print("{}: DH Hash Comparison from {} FAIL".format(self.id, packet.src)) # Extend always gets wrapped with everything in the the AES Keys list def get_extend_packet(self, receivers): msg = "Type: Extend" iniciopKp=time.time() extend_messages = {} for j in range(len(receivers) - 1): extend_messages[receivers[j]] = aes_encrypt(msg, self.aes_keys[receivers[j]]) def recursive_extend(recs, node_index): if node_index == len(recs) - 1: create_packet = self.get_create_packet(recs[node_index:]) create_packet.src = recs[node_index - 1] return create_packet return Packet(src_id="client", op=OP.EXTEND, dest=recs[0], payload=(extend_messages[recs[node_index]], recursive_extend(recs, node_index + 1))) packet = recursive_extend(receivers, 0) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') return packet
class Sender: def __init__(self): self._sock_to_receiver = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._sock_to_mb = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._df = DiffieHellman() self._df.generate_private_key() self._df.generate_public_key() self._session_key = None self._k = None self._k_rand = None def connect(self, address): """ The sender(S) in this connect method will attempt to connect to the receiver(R) by a regular sock connection. If the connection is set up successfully, S and R will execute a key exchange protocol then both of them will get a shared secret key. After that three keys (a session key Kssl, a key K used in our detection protocol, and a key Krand used as a seed) will be derived from this secret key. Then, S will try to connect to the middle- box by another regular sock connection. If the connection is set up successfully, S will execute a secure computation with MB so that MB can obtain rules encrypted with key K without knowing K. :param address: the receiver's address :return: """ try: self._sock_to_receiver.connect(address) except socket.error as error: print(f'Could not connect with the receiver: {error}') exit(1) except TypeError as error: print(f'Type error: {error}') exit(1) else: self._key_exchange(self._df.public_key) self._derive_from_secret() print('session key', self._session_key) try: self._sock_to_mb.connect(BLINDBOX_ADDRESS) except socket.error as error: print(f'Could not connect with blindBox: {error}') exit(1) except TypeError as error: print(f'Type error: {error}') exit(1) else: self._rule_preparation() def _key_exchange(self, public_key): """ After a key exchange using Diffie-Hellman algorithm, the sender will agree on a shared secret with the receiver. :param public_key: The sender's public key for key exchange. :return: None """ key_to_bytes = str(public_key).encode() self._sock_to_receiver.sendall(key_to_bytes) data = self._sock_to_receiver.recv(20480) print(f'data received from the receiver {data}') try: pk_from_receiver = int(data) except ValueError: print('Invalid data type!') else: if self._df.verify_public_key(pk_from_receiver): self._df.generate_shared_secret(pk_from_receiver) print('I got the shared key:', self._df.shared_key) else: raise ValueError('Invalid public key from the sender!') def _derive_from_secret(self): """ Use the shared key to derive three keys by using a pseudorandom generator. _session_key: used to encrypt the traffic in the socket. _k: used in the detection protocol _k_rand: used as a seed for randomness. Since both end-points have the same seed, they will generate the same randomness. :return: None """ key_to_bytes = str(self._df.shared_key).encode() randoms = Randoms() self._session_key = derive_key(key_to_bytes, randoms.random1) self._k = derive_key(key_to_bytes, randoms.random2) self._k_rand = derive_key(key_to_bytes, randoms.random3) def _rule_preparation(self): """ Sender will use garbled circuits to compute AES(r,k) with the BlindBox while the sender do not know the rule and the BlindBox do not know the key k. :return: """ key_numbers = int(self._sock_to_mb.recv(1024)) for i in range(key_numbers): output = subprocess.getoutput(OBLIVC_AES_PATH + "/a.out 1235 -- " + self._k.decode()) while output == "TCP accept failed": output = subprocess.getoutput(OBLIVC_AES_PATH + "/a.out 1235 -- " + self._k.decode()) def send(self, data): encrypted_data = aes_encrypt(data.encode(), self._session_key) self._sock_to_mb.sendall(encrypted_data) sleep(0.4) tokens = nltk.word_tokenize(data) encrypted_tokens = b'' for token in tokens: encrypted_tokens += dpi_encrypt(token.encode(), self._session_key) encrypted_tokens += b' ' self._sock_to_mb.sendall(encrypted_tokens)
def login_proto(self): print("something") Message = COMM_MESSAGE() data, temp = self.connection_from_client.recvfrom(4096) print(temp) Message.ParseFromString(data) if Message.type == Message.TYPE.LOGIN: N1 = os.urandom(16) N1 = N1.hex() print(N1) digest = sha256() digest.update(N1.encode()) Message.N1_hash = digest.hexdigest() Message.message = N1[5:] self.connection_from_client.sendall(Message.SerializeToString()) data, temp = self.connection_from_client.recvfrom(4096) print(temp) Message.ParseFromString(data) if Message.N1 == N1: print("Puzzle figured out!") else: print("Wrong!") bob = DiffieHellman(group=5, key_length=200) bob.generate_public_key() Message.gb_mod_p = str(bob.public_key) bob.generate_shared_secret(int(Message.message)) Kas = str(bob.shared_secret)[:16].encode() # Kas = (bob.shared_secret).to_bytes(16,sys.byteorder) print("Shared secret is:", int.from_bytes(Kas, sys.byteorder)) Message.gb_mod_p = str(bob.public_key) #### loading private key with open("private_key.pem", "rb") as key_file: private_key = serialization.load_pem_private_key( key_file.read(), password=None, backend=default_backend()) #### encryption plain_text_sign = Message.message + "|" + Message.gb_mod_p plain_text_sign = plain_text_sign.encode() ### sign the text signature = private_key.sign( plain_text_sign, paddings.PSS(mgf=paddings.MGF1(hashes.SHA256()), salt_length=paddings.PSS.MAX_LENGTH), hashes.SHA256()) #### Timestamp timestamp = str(int(time.time())) timestamp = timestamp.encode() plain_text = signature + timestamp iv = os.urandom(16) Message.iv = iv padder = padding.PKCS7(128).padder() padded_data = padder.update(plain_text) padded_data += padder.finalize() plain_text_padded = padded_data authenticate_data = b'Final Project' # self.Message.authenticate_data = authenticate_data # GCM Mode, we also need an IV # encrypt cipher = Cipher(algorithms.AES(Kas), modes.GCM(iv), backend=default_backend()) encryptor = cipher.encryptor() encryptor.authenticate_additional_data(authenticate_data) cipher_text = encryptor.update( plain_text_padded) + encryptor.finalize() Message.cipher_text = cipher_text Message.tag = encryptor.tag self.connection_from_client.sendall(Message.SerializeToString()) ### Decrypt and verify the client: data = self.connection_from_client.recv(4096) Message.ParseFromString(data) # AES decryption decryptor = Cipher(algorithms.AES(Kas), modes.GCM(iv, Message.tag), backend=default_backend()).decryptor() decryptor.authenticate_additional_data(authenticate_data) decrypted_plain_text = decryptor.update( Message.cipher_text) + decryptor.finalize() # unpad unpadder = padding.PKCS7(128).unpadder() plain_text = unpadder.update( decrypted_plain_text) + unpadder.finalize() # Verify timestamp plain_text_timestamp = plain_text[-10:] message_timestamp = int(plain_text_timestamp) if ((int(time.time()) - message_timestamp) < 60): print("Timestamp verified") else: print("Timestamp failed!") ### plain_text = plain_text[0:len(plain_text) - 10] plain_text = plain_text.decode() username = plain_text.split("|")[0] password = plain_text.split("|")[1] #if username == "Yushen" and password == "123": # verify = "Success" #else: # verify = "Fail" verify = "Fail" if username in self.identities.keys(): pass_digest = sha256() pass_digest.update(password.encode()) pass_digest.update(self.identities[username]["salt"].encode()) pass_hash = pass_digest.hexdigest() print(pass_hash, "is the passhash") if pass_hash == self.identities[username]["passhash"]: verify = "Success" #### plain_text = verify.encode() timestamp = str(int(time.time())) timestamp = timestamp.encode() plain_text = plain_text + timestamp padder = padding.PKCS7(128).padder() padded_data = padder.update(plain_text) padded_data += padder.finalize() plain_text_padded = padded_data cipher = Cipher(algorithms.AES(Kas), modes.GCM(iv), backend=default_backend()) encryptor = cipher.encryptor() encryptor.authenticate_additional_data(authenticate_data) cipher_text = encryptor.update( plain_text_padded) + encryptor.finalize() Message.cipher_text = cipher_text Message.tag = encryptor.tag self.connection_from_client.sendall(Message.SerializeToString()) # connection_from_client.shutdown(0) # self.socket_from_client.shutdown(0) self.connection_from_client.close() self.socket_from_client.close()
#!/usr/bin/env python3 # -*- coding: utf-8 -*- from diffiehellman.diffiehellman import DiffieHellman alice = DiffieHellman(group=18, key_length=1024) bob = DiffieHellman(group=18, key_length=1024) alice.generate_public_key() # automatically generates private key bob.generate_public_key() alice.generate_shared_secret(bob.public_key, echo_return_key=True) bob.generate_shared_secret(alice.public_key, echo_return_key=True) a = alice.shared_key b = bob.shared_key
class Client: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mujAES = None cli = None def __init__(self, adress='127.0.0.1'): self.sock.connect((adress, 9876)) self.cli = DiffieHellman() self.cli.generate_public_key() self.vyzadatKlic() iThread = threading.Thread(target=self.sendMessage) iThread.daemon = True iThread.start() self.run() def run(self): while True: data = self.sock.recv(BUFSIZE) #misto na hrani si s daty if not data: #ukonceni komunikace break elif data[0:1] == b"\x11": #kdyz prijde ridici znak x11-posleme na vyzadani klic self.poslatKlic() elif data[0:1] == b"\x12": #kdyz prijde ridici znak x12 tak si nastavime klic ktery nasleduje po tomto bytu self.nastavitKlic(data[1:]) elif data[0:1] == b"\x13": #nezasifrovana komunikace print(data.decode()) elif data[0:1] == b"\x14": #nastaveni klice v pripade ze byl vyzadan nebo tak neco self.jinenastaveniklice(data[1:]) else: #vychozi stav- prijdou data bez ridiciho znaku-> predpokladame ze jsou zasifrovana AESem podle dohodnuteho hesla data = self.mujAES.decrypt(data) print(data.decode()) def poslatKlic(self): #posle ridici znak nasledovany klicem self.sock.send(b'\x12' + str(self.cli.public_key).encode()) def jinenastaveniklice(self, data): #dela zajimave veci, ale jen v urcitem pripade self.cli.generate_shared_secret(int(data.decode()), echo_return_key=True) superklic = str(self.cli.shared_secret) xy = hashlib.sha256(superklic.encode()).hexdigest()[:32] print("2222222222222222222222222222") print(xy) self.mujAES = Encryptor(xy) def nastavitKlic(self, data): #nastavuje klic na zaklade dat ktere dostane self.cli.generate_shared_secret(int(data.decode()), echo_return_key=True) superklic = str(self.cli.shared_secret) xy = hashlib.sha256(superklic.encode()).hexdigest()[:32] print("111111111111111111111") print(xy) self.mujAES = Encryptor(xy) self.sock.send(b'\x14' + str(self.cli.public_key).encode()) def vyzadatKlic(self): #nemam klic ale chci, poslu ridici znak self.sock.send(b'\x11') def sendMessage(self): #hlavni chatova smycka while True: msg = str(input("")) if self.mujAES is not None: msg = self.mujAES.encrypt(msg.encode()) self.sock.send(msg) else: msg = msg.encode() self.sock.send(b'\x13' + msg)
import socket from Crypto.Cipher import AES from Crypto.Hash import SHA256 from Crypto import Random import base64 import random from diffiehellman.diffiehellman import DiffieHellman #testar mig fram alice = DiffieHellman() alice.generate_public_key() UDP_IP = "127.0.0.1" UDP_PORT = 5005 print("UDP target IP:",UDP_IP) print("UDP target port:",UDP_PORT) print("Public key: ", alice.public_key) # Code stolen from: https://stackoverflow.com/questions/12524994/encrypt-decrypt-using-pycrypto-aes-256 #-------------------------------------------------------------------------------------------------------- BS=16 pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) def encrypt(raw): raw = pad(raw) iv = Random.new().read(AES.block_size) cipher = AES.new(hash, AES.MODE_CBC, iv) return base64.b64encode(iv + cipher.encrypt(raw.encode("utf8"))) #--------------------------------------------------------------------------------------------------------
class Receiver: def __init__(self): self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._sock_to_mb = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._sock.bind(ADDRESS) self._sock.listen(10) self._df = DiffieHellman() self._df.generate_private_key() self._df.generate_public_key() self._session_key = None self._k = None self._k_rand = None def connection_setup(self): while True: # Wait for a connection connection, address = self._sock.accept() self._key_exchange(connection, self._df.public_key) print('My shared key:', self._df.shared_key) self._derive_from_secret() print('session key', self._session_key) try: self._sock_to_mb.connect(BLINDBOX_ADDRESS) except socket.error as error: print(f'Could not connect with blindBox: {error}') exit(1) except TypeError as error: print(f'Type error: {error}') exit(1) else: self._rule_preparation() def _key_exchange(self, connection, public_key): """ After a key exchange using Diffie-Hellman algorithm, the sender will agree on a shared secret with the receiver. :param public_key: The sender's public key for key exchange. :return: None """ data = connection.recv(20480) print(f'data received from the sender: {data}') try: pk_from_sender = int(data) except ValueError: print('Invalid data type!') else: if self._df.verify_public_key(pk_from_sender): self._df.generate_shared_secret(pk_from_sender) print('I got the shared key:', self._df.shared_key) connection.sendall(str(public_key).encode()) else: raise ValueError('Invalid public key from the sender!') def _derive_from_secret(self): """ Use the shared secret to derive three keys by using a pseudorandom generator. _session_key: used to encrypt the traffic in the socket. _k: used in our detection protocol _k_rand: used as a seed for randomness. Since both end-points have the same seed, they will generate the same randomness. :return: None """ key_to_bytes = str(self._df.shared_key).encode() randoms = Randoms() self._session_key = derive_key(key_to_bytes, randoms.random1) self._k = derive_key(key_to_bytes, randoms.random2) self._k_rand = derive_key(key_to_bytes, randoms.random3) def _rule_preparation(self): """ Sender will use garbled circuits to compute AES(r,k) with the BlindBox while the sender do not know the rule and the BlindBox do not know the key k. :return: """ key_numbers = int(self._sock_to_mb.recv(1024)) for i in range(key_numbers): output = subprocess.getoutput(OBLIVC_AES_PATH + "/a.out 5321 -- " + self._k.decode()) while output == "TCP accept failed": output = subprocess.getoutput(OBLIVC_AES_PATH + "/a.out 5321 -- " + self._k.decode()) def receive(self): encrypted_traffic = self._sock_to_mb.recv(20480) encrypted_tokens = self._sock_to_mb.recv(20480) traffic = aes_decrypt(encrypted_traffic) self.check_tokens(traffic, encrypted_tokens) def check_tokens(self, traffic, encrypted_tokens): pass
class TestDiffieHellman(unittest.TestCase): def setUp(self): self.alice = DiffieHellman() self.bob = DiffieHellman() def test_equality_of_keys(self): self.alice.generate_public_key() self.bob.generate_public_key() alices_shared_key = self.alice.generate_shared_secret(self.bob.public_key) bobs_shared_key = self.bob.generate_shared_secret(self.alice.public_key) self.assertEqual(alices_shared_key, bobs_shared_key, "There is a mismatch between two shared secrets. Both shared secrets should be the same. This is bad.") def test_decorators_private_key(self): self.alice.generate_public_key() self.assertIn("_DiffieHellman__private_key", self.alice.__dict__) def test_generate_private_key(self): self.alice.generate_private_key() self.assertIn("_DiffieHellman__private_key", self.alice.__dict__) def test_generate_public_key(self): self.alice.generate_public_key() self.assertIn("public_key", self.alice.__dict__) def test_verify_public_key(self): self.alice.generate_public_key() self.bob.generate_public_key() self.assertTrue(self.alice.verify_public_key(self.bob.public_key)) self.assertFalse(self.alice.verify_public_key(2)) self.assertFalse(self.alice.verify_public_key(self.alice.prime - 1))
class ClientCipher: def __init__(self, mode, hmac_hash_type): self.mode = mode self.hmac_hash_type = hmac_hash_type # store client app keys self.client_app_keys = self.generate_keys() # load server pub. key self.server_pub_key = serialization.load_pem_public_key( open(SERVER_PUB_KEY, "rb").read(), backend=default_backend()) # Diffie Hellman self.client_dh = None # save session key self.session_key = None # warrant nounces self.warrant_nounces = {} # how many requests were made to the server self.request_to_server = 1 def generate_keys(self): private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) public_key = private_key.public_key() return private_key, public_key """ ASYMMETRIC CIPHER """ def asym_cipher(self, pub_key, raw_data): pickle_dumps = pickle.dumps(raw_data) return pub_key.encrypt( pickle_dumps, _aspaadding.OAEP(mgf=_aspaadding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)) def asym_decipher(self, private_key, ciphered_data): data = private_key.decrypt( ciphered_data, _aspaadding.OAEP(mgf=_aspaadding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)) return pickle.loads(data) def asym_sign(self, private_key, data): return private_key.sign( data, _aspaadding.PSS(mgf=_aspaadding.MGF1(hashes.SHA256()), salt_length=_aspaadding.PSS.MAX_LENGTH), hashes.SHA256()) def asym_validate_sign(self, data, sign_data, public_key): verifier = public_key.verifier( sign_data, _aspaadding.PSS(mgf=_aspaadding.MGF1(hashes.SHA256()), salt_length=_aspaadding.PSS.MAX_LENGTH), hashes.SHA256()) verifier.update(data) return verifier.verify() """ SYMMETRIC KEY CIPHER """ def sym_cipher(self, obj, ks, iv=os.urandom(16), mode=None): """ :param iv: key to cipher the object :param obj: object to be ciphered :param ks: key to cipher the object :param mode: """ if mode is None: mode = modes.CTR cipher = Cipher(algorithms.AES(ks), mode(iv), backend=default_backend()) # pickle makes the serialization of the object pickle_dumps = pickle.dumps( [obj, os.urandom(RANDOM_ENTROPY_GENERATOR_SIZE)]) # encrypt obj dumped data encryptor = cipher.encryptor() ciphered_obj = encryptor.update(pickle_dumps) + encryptor.finalize() return iv, ciphered_obj def sym_decipher(self, obj, ks, iv, mode=None): """ :param obj: :param ks: :param iv: :param mode: :return: """ if mode is None: mode = modes.CTR cipher = Cipher(algorithms.AES(ks), mode(iv), backend=default_backend()) decryptor = cipher.decryptor() deciphered_data = decryptor.update(obj) + decryptor.finalize() data, random = pickle.loads(deciphered_data) return data """ HYBRID A-SYMMETRIC KEY CIPHER """ def hybrid_decipher(self, obj, private_key, ks=None): obj, random_pickle = pickle.loads(base64.b64decode(obj)) # decipher using rsa private key if ks is None: ks = self.asym_decipher(private_key, base64.b64decode(obj["key"])) # decipher using rsa private key iv = self.asym_decipher(private_key, base64.b64decode(obj["iv"])) # decipher using symmetric AES CTR return self.sym_decipher(base64.b64decode(obj["obj"]), ks, iv) def hybrid_cipher(self, obj, public_key, ks=os.urandom(32), cipher_key=True): # cipher using symmetric cipher AES CTR # returns the ciphered obj with the IV iv, ciphered_obj = self.sym_cipher(obj, ks) # iv ciphered with the public key iv_encrypted = self.asym_cipher(public_key, iv) # key ciphered with the public_key if cipher_key: # send ks to the server key_encrypted = self.asym_cipher(public_key, ks) pickle_dumps = pickle.dumps( [{ "obj": base64.b64encode(ciphered_obj).decode(), "iv": base64.b64encode(iv_encrypted).decode(), "key": base64.b64encode(key_encrypted).decode() }, os.urandom(RANDOM_ENTROPY_GENERATOR_SIZE)]) return base64.b64encode(pickle_dumps) else: pickle_dumps = pickle.dumps( [{ "obj": base64.b64encode(ciphered_obj).decode(), "iv": base64.b64encode(iv_encrypted).decode() }, os.urandom(RANDOM_ENTROPY_GENERATOR_SIZE)]) return base64.b64encode(pickle_dumps) """ KEY DERIVATION FUNCTION GIVEN THE MASTER KEY """ def key_derivation(self, masterkey, salt=os.urandom(32), iterations=100000): kdf = PBKDF2HMAC(algorithm=hashes.SHA512(), length=32, salt=salt, iterations=iterations, backend=default_backend()) return kdf.derive(masterkey), salt """ HMAC - create """ def hmac_update_finalize(self, key, data): if not isinstance(key, bytes) and isinstance(key, str): key = key.encode() if not isinstance(data, bytes): data = pickle.dumps(data) h = hmac.HMAC(key, self.hmac_hash_type(), backend=default_backend()) h.update(data) return h.finalize() """ HMAC - verify """ def hmac_verify(self, key, hmac_data, data): if not isinstance(key, bytes) and isinstance(key, str): key = key.encode() if not isinstance(data, bytes): data = pickle.dumps(data) h = hmac.HMAC(key, self.hmac_hash_type(), backend=default_backend()) h.update(data) return h.verify(hmac_data) """ SECURE LAYER ENCAPSULATION """ def secure_layer_encrypt(self, msg: bytes): # generate a nounce that will be a warrant of the message # the nounce will be stored with the respective session key iteration # after retrieved it will be deleted and then the message exchanged between # the server and the client will be never deciphered again nounce = sha256(json.dumps(msg).encode() + os.urandom(32)).hexdigest().encode() key, salt = self.key_derivation(self.session_key, iterations=self.request_to_server) iv = os.urandom(16) # saving the iterations ans salt used for the given nounce self.warrant_nounces[nounce] = { "iterations": self.request_to_server, "salt": salt, "seq": self.request_to_server } # salt (the salt used to the KDF), nounce (the genuineness warrant), iv (used in the cipher) sec_data = pickle.dumps({ "salt": salt, "nounce": nounce, "iv": iv, "seq": self.request_to_server }) # sec_data ciphered sec_data_ciphered = self.hybrid_cipher(sec_data, self.server_pub_key) # HMAC hmac_key = sha256(key).hexdigest() hmac_data = self.hmac_update_finalize(hmac_key, msg) msg = [msg, hmac_data] pickle_dumps = pickle.dumps(msg) # cipher with symmetric cipher the message content iv, ciphered_obj = self.sym_cipher(pickle_dumps, key, iv=iv, mode=self.mode) # message to be signed and sent to the server return_message = { "data": base64.b64encode(ciphered_obj).decode(), "sec_data": base64.b64encode(sec_data_ciphered).decode() } self.request_to_server += 1 # dump the return message pickle_dumps = pickle.dumps(return_message) return base64.b64encode(pickle_dumps) def secure_layer_decrypt(self, msg: bytes): msg = pickle.loads(base64.b64decode(msg)) # get sec_data content sec_data = pickle.loads( self.hybrid_decipher(base64.b64decode(msg["sec_data"]), self.client_app_keys[0])) nounce = sec_data["nounce"] if nounce not in self.warrant_nounces: print( "Something went wrong with the nounce in the secure layer decrypt." ) exit(1) if sec_data["seq"] != (self.warrant_nounces[nounce]["seq"] + 1): print("Received wrong sequence number by the server") exit(1) # the nounce warrant allow us to retrieve the iterations and the salt used to derive the key iterations = self.warrant_nounces[nounce]["iterations"] salt = self.warrant_nounces[nounce]["salt"] # now it can be deleted del self.warrant_nounces[nounce] key, salt = self.key_derivation(self.session_key, iterations=iterations, salt=salt) raw_msg = pickle.loads( self.sym_decipher(base64.b64decode(msg["data"]), ks=key, iv=sec_data["iv"], mode=self.mode)) # verify hmac hmac_key = sha256(key).hexdigest() self.hmac_verify(hmac_key, raw_msg[1], raw_msg[0]) return raw_msg[0] """ CLIENT SERVER SESSION KEY NEGOTIATION """ def negotiate_session_key(self, phase, val=None): """ First the Application loads the server public key that is distributed into the client application. It's ok to publicly distribute the Public Key but it must be verified if the public key of the server is still the same. If not, it must be updated. Another way is to request the public key of the server and ask for the user fingerprint verification. {verification missing} After that, the client app generate DH values (private and public) to exchange with the server in order to get the shared secret session key. Phase 1: [CLIENT]: send generated DH public key to the server (signed) and the app client rsa public key (signed too). The sent values will be ciphered with a random key and signed. Phase 2: [SERVER]: the server generates the private and public DH pair. Then using the server private key, the server decipher the DH public received encrypted value. Using again the server private key, the server deciphers the client public key and loads it into memory. Then, using the client public key, validates the signature made for the DH public value and public key received. Using the received client public key, the server will make a hybrid cipher (AES and RSA) of the DH server generated public key. After the cipher, the server will sign with the server private key the data ciphered. Phase 3: [CLIENT]: using the stored server public key the client will validate the signature received. After that using the client private key, the client will decipher the DH public value received from the server. Then using the DH public value, the client will generate the DH shared secret and using PBKDF2HMAC will use a key derivation function. The master key will be the secret DH shared value and will have 100 000 iterations. The salt is random and so, it will be ciphered and sent to the server. The session key has been generated. Phase 4: [SERVER]: Using the client public key it will be verified the signature of the received value. Using the server private key and a hybrid cipher the PBKDF2 salt will be deciphered. Using the key derivation function the session key will be obtained in the server. Then, there is a secure channel between the server and the client. :param val: value sent by the server :param phase: 1, 2, 3 or 4 :return: value to send to the server """ if phase == 1: # client generate DH private and public key self.client_dh = DiffieHellman(key_length=256) self.client_dh.generate_public_key() # cipher DH public key with server pub. key # cipher the client DH public key client_dh_ciphered = self.hybrid_cipher(self.client_dh.public_key, self.server_pub_key) # cipher the client public key pem = self.client_app_keys[1].public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) client_public_key_ciphered = self.hybrid_cipher( pem, self.server_pub_key) return { "data": client_dh_ciphered.decode(), "data_signature": base64.b64encode( self.asym_sign(self.client_app_keys[0], client_dh_ciphered)).decode(), "public_key": client_public_key_ciphered.decode(), "public_key_signature": base64.b64encode( self.asym_sign(self.client_app_keys[0], client_public_key_ciphered)).decode(), "phase": 2, "cipher": "AES&RSA", "mode": self.mode.name, "hmac_hash": self.hmac_hash_type.name } elif phase == 3: # validate the DH received value self.asym_validate_sign( val["data"].encode(), base64.b64decode(val["data_signature"].encode()), self.server_pub_key) # decipher the received DH value server_dh_pub = self.hybrid_decipher(val["data"], self.client_app_keys[0]) # generate shared secret (client session key) self.client_dh.generate_shared_secret(server_dh_pub) # save the session key self.session_key, salt = self.key_derivation( str(self.client_dh.shared_secret).encode()) salt_ciphered = self.hybrid_cipher(salt, self.server_pub_key) return { "phase": 4, "data": salt_ciphered.decode(), "data_signature": base64.b64encode( self.asym_sign(self.client_app_keys[0], salt_ciphered)).decode() }
class TestDiffieHellman(unittest.TestCase): def setUp(self): self.alice = DiffieHellman() self.bob = DiffieHellman() def test_equality_of_keys(self): self.alice.generate_public_key() self.bob.generate_public_key() alices_shared_key = self.alice.generate_shared_secret( self.bob.public_key) bobs_shared_key = self.bob.generate_shared_secret( self.alice.public_key) self.assertEqual( alices_shared_key, bobs_shared_key, "There is a mismatch between two shared secrets. Both shared secrets should be the same. This is bad." ) def test_decorators_private_key(self): self.alice.generate_public_key() self.assertIn("_DiffieHellman__private_key", self.alice.__dict__) def test_generate_private_key(self): self.alice.generate_private_key() self.assertIn("_DiffieHellman__private_key", self.alice.__dict__) def test_generate_public_key(self): self.alice.generate_public_key() self.assertIn("public_key", self.alice.__dict__) def test_verify_public_key(self): self.alice.generate_public_key() self.bob.generate_public_key() self.assertTrue(self.alice.verify_public_key(self.bob.public_key)) self.assertFalse(self.alice.verify_public_key(2)) self.assertFalse(self.alice.verify_public_key(self.alice.prime - 1))
def handle_sock(self, sock, addr): # sock 的流程 ############################## #### Handle a new request##### #### ##### ############################## while True: data = sock.recv(4096) # print ("I have received a new message!") MessageRec = COMM_MESSAGE() MessageRec.ParseFromString(data) if (MessageRec.type == COMM_MESSAGE.TYPE.LOGOUT): plain_text = self.decryption_with_timestamp_in_client( MessageRec, self.socket_from_list[src][1], self.socket_from_list[src][2]) plain_text = plain_text.decode() print("I received log out request_1") print(plain_text) if (plain_text == "log out"): MessageSend = COMM_MESSAGE() MessageSend.type = COMM_MESSAGE.TYPE.CONFIRM plain_text = 'log out confirmed'.encode() + str( int(time.time())).encode() MessageSend = self.encryption_in_client( MessageSend, self.socket_from_list[src][1], self.socket_from_list[src][2], plain_text) self.socket_from_list[src][0].sendall( MessageSend.SerializeToString()) self.socket_from_list[src][0].close() del self.socket_from_list[src] del self.user_online[src] if (MessageRec.type == COMM_MESSAGE.TYPE.CLIENT_TO_CLIENT): plain_text = self.decryption_of_ticket_with_timestamp( MessageRec.ticket, MessageRec.ticket_tag) plain_text = plain_text.decode() src = plain_text.split(" ")[0] # self.socket_from_list[src] = [] # self.socket_from_list[src].append (sock) kab_temp = plain_text.split(" ")[1].encode() iv_temp = plain_text.split(" ")[2].encode() plain_text = self.decryption_with_timestamp_in_client( MessageRec, kab_temp, iv_temp) plain_text = plain_text.decode() N1 = int(plain_text) y = os.urandom(8) x = y.hex() N2 = int(x, 16) plain_text = (str(N1 - 1) + " " + str(N2)).encode() + str( int(time.time())).encode() # .encode() + " ".encode + str(N2).encode() MessageSend = COMM_MESSAGE() bob = DiffieHellman(group=5, key_length=200) bob.generate_public_key() MessageSend.gb_mod_p = str(bob.public_key) MessageSend = self.encryption_in_client( MessageSend, kab_temp, iv_temp, plain_text) sock.sendall(MessageSend.SerializeToString()) MessageRec = COMM_MESSAGE() data = sock.recv(4096) MessageRec.ParseFromString(data) plain_text = self.decryption_with_timestamp_in_client( MessageRec, kab_temp, iv_temp) N2_rec = int(plain_text.decode()) if N2 - 1 == N2_rec: bob.generate_shared_secret(int(MessageRec.message)) kas = str(bob.shared_secret)[:16].encode() # self.socket_list[src].append(str(bob.shared_secret)[:16].encode()) temp = os.urandom(16) iv = temp.hex()[:16].encode() # self.socket_list[src].append(iv) plain_text = ("Confirm " + self.client_name).encode() + str( int(time.time())).encode() MessageSend = COMM_MESSAGE() MessageSend.iv = iv MessageSend = self.encryption_in_client( MessageSend, kas, iv, plain_text) sock.sendall(MessageSend.SerializeToString()) MessageRec = COMM_MESSAGE() data = sock.recv(4096) MessageRec.ParseFromString(data) plain_text = self.decryption_with_timestamp_in_client( MessageRec, kas, iv) plain_text = plain_text.decode() if plain_text.split( " ")[0] == "Confirm" and plain_text.split( " ")[1] == src: client_sk = socket.socket() client_sk.connect(('127.0.0.1', addr[1])) # print ("I will use this socket to talk to",src,":", client_sk) self.socket_from_list[src] = [] self.socket_from_list[src].append(client_sk) self.socket_from_list[src].append(kas) self.socket_from_list[src].append(iv) # print("I have succeed in setting up connection with", src, "with session key:", kas) # print("We use this socket to chatting:", sock) else: print("The adversary modify the CONFIRM message") else: print("N2 puzzle wrong!") sys.exit(1) else: plain_text = self.decryption_with_timestamp_in_client( MessageRec, self.socket_from_list[src][1], self.socket_from_list[src][2]) plain_text = plain_text.decode() print("From", src, ":", plain_text)
class EncryptionPacket: PACKET_MAGIC_CODE = struct.pack('>BBBB', 0x43, 0x52, 0x59, 0x54) FUNCTION_INITIALIZE_HANDSHAKE = 0x00 FUNCTION_SECURE_COMMUNICATION = 0x02 def __init__(self, device, other): self.device = device self.other = other self._user = None def generate_key(self): self._user = DiffieHellman() self._user.generate_public_key() def send_complete_public_data(self): data = bytearray(EncryptionPacket.PACKET_MAGIC_CODE) + struct.pack( ">BB", EncryptionPacket.FUNCTION_INITIALIZE_HANDSHAKE, 0x55) self.other.send(data) def recv_public_data(self, data): hash_length = data[0] hash_value = data[1:hash_length + 1] hash_str = str() for i in range(0, len(hash_value)): hash_str += '{:02x}'.format(int(hex(hash_value[i]), 16)) print("Digest: {}".format(hash_str)) public_key_data = data[hash_length + 1:] public_key = str() for i in range(0, len(public_key_data)): public_key += '{:02X}'.format(int(hex(public_key_data[i]), 16)) m = hashlib.sha256() m.update(public_key.encode('utf-8')) other_hash_value = m.hexdigest() print("Calculated digest: {}".format(other_hash_value)) # the public key is not matched if hash_str != other_hash_value: return -1 # Convert str to big-integer received_public_key = int(public_key) self._user.generate_shared_secret(received_public_key) print("Shared key: {}".format(self._user.shared_key)) return 0 def init_encryption_data(self, generated=True, mode=0): if generated: self.generate_key() if self.other is None: raise ConnectionError("You need to connect the other deivce!") else: print("Initializing encryption handshake ...", end='') key = str(self._user.public_key) key_array = bytearray() for i in range(0, len(key), 2): hex_number = key[i:i + 2] hex_number = '0x' + str(hex_number) key_array += struct.pack(">B", int(hex_number, base=16)) print("Generated public key -> len=[{}]".format(len(key_array))) print("Sending the public key ...") m = hashlib.sha256() m.update(key.encode('utf-8')) result_hash = m.hexdigest() result_hash_array = bytearray() for i in range(0, len(result_hash), 2): hex_number = result_hash[i:i + 2] hex_number = '0x' + str(hex_number) result_hash_array += struct.pack(">B", int(hex_number, base=16)) fih = struct.pack(">B", EncryptionPacket.FUNCTION_INITIALIZE_HANDSHAKE) hash_str_length = struct.pack(">B", len(result_hash_array)) self.other.send(EncryptionPacket.PACKET_MAGIC_CODE + fih + struct.pack(">B", mode) + hash_str_length + result_hash_array + key_array) if mode == 0: print("Awaiting the received public key ...")
def client_setup_connection(self, dest): client_sk = socket.socket() client_sk.connect(('127.0.0.1', int(self.user_online[dest][1]))) self.socket_list[dest] = [] self.socket_list[dest].append(client_sk) port = client_sk.getsockname()[1] # print ("Port is:", port) server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(("127.0.0.1", port)) ######################### ### Set up ###### ### the connection ###### ######################### MessageSend = COMM_MESSAGE() MessageRec = COMM_MESSAGE() MessageSend.type = COMM_MESSAGE.TYPE.CLIENT_TO_CLIENT MessageSend.ticket = self.user_online[dest][4] MessageSend.ticket_tag = self.user_online[dest][5] kabtemp = self.user_online[dest][2].encode() ivtemp = self.user_online[dest][3].encode() y = os.urandom(8) x = y.hex() N1 = int(x, 16) plain_text = str(N1).encode() + str(int(time.time())).encode() MessageSend = self.encryption_in_client(MessageSend, kabtemp, ivtemp, plain_text) self.socket_list[dest][0].sendall(MessageSend.SerializeToString()) data = self.socket_list[dest][0].recv(4096) MessageRec.ParseFromString(data) plain_text = self.decryption_with_timestamp_in_client( MessageRec, kabtemp, ivtemp) plain_text = plain_text.decode() N1_rec = int(plain_text.split(" ")[0]) if N1 - 1 == N1_rec: MessageSend = COMM_MESSAGE() MessageSend.type = COMM_MESSAGE.TYPE.CLIENT_TO_CLIENT ### Set up the new Kab ### alice = DiffieHellman(group=5, key_length=200) alice.generate_public_key() MessageSend.message = str(alice.public_key) alice.generate_shared_secret(int(MessageRec.gb_mod_p)) # set up the session key Kas self.socket_list[dest].append( str(alice.shared_secret)[:16].encode()) N2_rec = int(plain_text.split(" ")[1]) N2_send = N2_rec - 1 plain_text = str(N2_send).encode() + str(int(time.time())).encode() MessageSend.iv = self.user_online[dest][3].encode() MessageSend = self.encryption_in_client(MessageSend, kabtemp, ivtemp, plain_text) self.socket_list[dest][0].sendall(MessageSend.SerializeToString()) data = self.socket_list[dest][0].recv(4096) MessageRec.ParseFromString(data) plain_text = self.decryption_with_timestamp_in_client( MessageRec, self.socket_list[dest][1], MessageRec.iv) plain_text = plain_text.decode() if plain_text.split(" ")[0] == "Confirm" and plain_text.split( " ")[1] == dest: self.socket_list[dest].append(MessageRec.iv) plain_text = ("Confirm " + self.client_name).encode() + str( int(time.time())).encode() MessageSend = COMM_MESSAGE() MessageSend.type = COMM_MESSAGE.TYPE.CLIENT_TO_CLIENT MessageSend.iv = self.socket_list[dest][2] self.socket_list[dest].append(server) client_thread_listen_from_existing_connection = threading.Thread( target=self.listen_from_existed_connection, args=(dest, )) # 把sock 加入线程内 client_thread_listen_from_existing_connection.start() # 启动线程 MessageSend = self.encryption_in_client( MessageSend, self.socket_list[dest][1], self.socket_list[dest][2], plain_text) self.socket_list[dest][0].sendall( MessageSend.SerializeToString()) # print ("I have succeed in setting up connection with", dest) # print("We use this socket to chatting:", self.socket_list[dest][0]) else: print("Set up connection with", dest, "failed!") sys.exit(1) else: print("N1 verify failed!") sys.exit(1)
import sys import crypto import time from diffiehellman.diffiehellman import DiffieHellman host = 'localhost' port = 501 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', 501)) data = 'CRYT'.encode('utf-8') dh = DiffieHellman() dh.generate_public_key() # Generate user ep = packet.EncryptionPacket(None, sock) ep._user = dh # Handshake sock.send(data + struct.pack(">B", 0x00)) time.sleep(0.3) # receiving initialize public key data = sock.recv(2048) ep.recv_public_data(data[6:]) time.sleep(0.3)
class Node: def __init__(self, id): self.setup_keys() self.connect_to_signals() self.id = id self.send_ops = { OP.CREATED: self.get_created_packet, OP.EXTENDED: self.get_extended_packet } self.hop_table = {1: HopPair(prev=None, next=None)} def setup_keys(self): self.dhke = DiffieHellman(key_length=1024) self.dhke.generate_public_key() self.__dh_sharedkey = None self.dh_pub = str(self.dhke.public_key).encode('utf8') (self.pubkey, self.__privkey) = rsa.newkeys(1024) def connect_to_signals(self): dispatcher.connect(self.handle_extend, signal=OP.EXTEND, sender=dispatcher.Any) dispatcher.connect(self.handle_create, signal=OP.CREATE, sender=dispatcher.Any) dispatcher.connect(self.handle_created, signal=OP.CREATED, sender=dispatcher.Any) def handle_extend(self, packet): if packet.dest != self.id: return None iniciopKp=time.time() print("{}: Handling EXTEND packet from {}".format(self.id, packet.src)) if packet.decrypt_aes(self.__dh_sharedkey): print("{}: Decryption of EXTEND packet from {} SUCCESS".format(self.id, packet.src)) forward_packet = packet.payload self.hop_table[1].next = packet.dest dispatcher.send(signal=forward_packet.op, sender=self, packet=forward_packet) return print("{}: Decryption of EXTEND packet from {} FAIL".format(self.id, packet.src)) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') def handle_create(self, packet): if packet.dest != self.id: return None iniciopKp=time.time() print("{}: Handling CREATE packet from {}".format(self.id, packet.src)) if not packet.decrypt_rsa(self.__privkey): print("{}: Decryption of CREATE packet from {} FAIL".format(self.id, packet.src)) return print("{}: Decryption of CREATE packet from {} SUCCESS".format(self.id, packet.src)) other_key = int(packet.payload) self.dhke.generate_shared_secret(other_key) self.__dh_sharedkey = self.dhke.shared_key self.hop_table[1].prev = packet.src self.send_packet(self.hop_table[1].prev, OP.CREATED) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') def send_packet(self, receiver, op, payload=None): iniciopKp=time.time() packet = self.send_ops[op](receiver, payload) dispatcher.send(signal=op, sender=self, packet=packet) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') def get_created_packet(self, receiver, payload=None): iniciopKp=time.time() key_hash = hashlib.sha1( str(self.__dh_sharedkey).encode("utf-8")).hexdigest() msg = (self.dhke.public_key, key_hash) packet = Packet(src_id=self.id, op=OP.CREATED, dest=receiver, payload=(msg, None)) print("{}: Sending CREATED packet to {}".format(self.id, receiver)) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') return packet def get_extended_packet(self, receiver, payload): iniciopKp=time.time() packet = Packet(self.id, OP.EXTENDED, receiver, payload) print("{}: Sending EXTENDED packet to {}".format(self.id, receiver)) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') return packet def handle_created(self, packet): if packet.dest != self.id: return None iniciopKp=time.time() print("{}: Handling CREATE packet from {}".format(self.id, packet.src)) dh_pub_key, key_hash = packet.msg encrypted_dh_pair = aes_encrypt("{}|||{}".format(dh_pub_key, key_hash), self.__dh_sharedkey) self.send_packet(self.hop_table[1].prev, OP.EXTENDED, (encrypted_dh_pair, None)) finpKp=time.time() print('########## Tiempo ##########:',(finpKp-iniciopKp), 'segundos') def __str__(self): return self.id
from diffiehellman.diffiehellman import DiffieHellman CERT = os.getcwd()+'/certs/cert.pem' server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server = ssl.wrap_socket(server,cert_reqs=ssl.CERT_REQUIRED, ca_certs = CERT) server.settimeout(5) IP_address = '192.168.168.184' Port = 8202 server.connect((IP_address, Port)) bob = DiffieHellman() bob.generate_public_key() x = {"bob":bob.public_key} server.send(json.dumps(x).encode("utf-8")) total_data="" # ########################################## REC ############################################# while True: try: message = "" message = server.recv(100) while message is not "": total_data+=message.decode("utf-8") message = "" message = server.recv(100) else: break except socket.error as ex:
class ServerCipher: def __init__(self): # load server pub. key self.server_pub_key = serialization.load_pem_public_key( open(SERVER_PUB_KEY, "rb").read(), backend=default_backend()) # load server priv. key self.server_priv_key = serialization.load_pem_private_key( open(SERVER_PRIV_KEY, "rb").read(), password=None, backend=default_backend()) # Diffie Hellman self.server_dh = None # session key self.session_key = None # client public key self.client_public_key = None # number of requests received self.requests_received = 1 # load cc libraries self.cc = CitizenCard() # mode CTR, CFB, OFB self.mode = None """ ASYMMETRIC CIPHER """ def asym_cipher(self, pub_key, raw_data): pickle_dumps = pickle.dumps(raw_data) return pub_key.encrypt( pickle_dumps, _aspaadding.OAEP(mgf=_aspaadding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)) def asym_decipher(self, private_key, ciphered_data): data = private_key.decrypt( ciphered_data, _aspaadding.OAEP(mgf=_aspaadding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)) return pickle.loads(data) def asym_sign(self, private_key, data): return private_key.sign( data, _aspaadding.PSS(mgf=_aspaadding.MGF1(hashes.SHA256()), salt_length=_aspaadding.PSS.MAX_LENGTH), hashes.SHA256()) def asym_validate_sign(self, data, sign_data, public_key): verifier = public_key.verifier( sign_data, _aspaadding.PSS(mgf=_aspaadding.MGF1(hashes.SHA256()), salt_length=_aspaadding.PSS.MAX_LENGTH), hashes.SHA256()) verifier.update(data) return verifier.verify() """ SYMMETRIC KEY CIPHER """ def sym_cipher(self, obj, ks, iv=os.urandom(16), mode=None): """ :param iv: key to cipher the object :param obj: object to be ciphered :param ks: key to cipher the object """ if mode is None: mode = modes.CTR cipher = Cipher(algorithms.AES(ks), mode(iv), backend=default_backend()) # pickle makes the serialization of the object pickle_dumps = pickle.dumps( [obj, os.urandom(RANDOM_ENTROPY_GENERATOR_SIZE)]) # encrypt obj dumped data encryptor = cipher.encryptor() ciphered_obj = encryptor.update(pickle_dumps) + encryptor.finalize() return iv, ciphered_obj def sym_decipher(self, obj, ks, iv, mode=None): """ :param obj: :param ks: :param iv: :return: """ if mode is None: mode = modes.CTR cipher = Cipher(algorithms.AES(ks), mode(iv), backend=default_backend()) decryptor = cipher.decryptor() deciphered_data = decryptor.update(obj) + decryptor.finalize() data, random = pickle.loads(deciphered_data) return data """ HYBRID A-SYMMETRIC KEY CIPHER """ def hybrid_decipher(self, obj, private_key, ks=None): obj, random_pickle = pickle.loads(base64.b64decode(obj)) # decipher using rsa private key if ks is None: ks = self.asym_decipher(private_key, base64.b64decode(obj["key"])) # decipher using rsa private key iv = self.asym_decipher(private_key, base64.b64decode(obj["iv"])) # decipher using symmetric AES CTR return self.sym_decipher(base64.b64decode(obj["obj"]), ks, iv) def hybrid_cipher(self, obj, public_key, ks=os.urandom(32), cipher_key=True): # cipher using symmetric cipher AES CTR # returns the ciphered obj with the IV iv, ciphered_obj = self.sym_cipher(obj, ks) # iv ciphered with the public key iv_encrypted = self.asym_cipher(public_key, iv) # key ciphered with the public_key if cipher_key: # send ks to the server key_encrypted = self.asym_cipher(public_key, ks) pickle_dumps = pickle.dumps( [{ "obj": base64.b64encode(ciphered_obj).decode(), "iv": base64.b64encode(iv_encrypted).decode(), "key": base64.b64encode(key_encrypted).decode() }, os.urandom(RANDOM_ENTROPY_GENERATOR_SIZE)]) return base64.b64encode(pickle_dumps) else: pickle_dumps = pickle.dumps( [{ "obj": base64.b64encode(ciphered_obj).decode(), "iv": base64.b64encode(iv_encrypted).decode() }, os.urandom(RANDOM_ENTROPY_GENERATOR_SIZE)]) return base64.b64encode(pickle_dumps) """ KEY DERIVATION FUNCTION GIVEN THE MASTER KEY """ def key_derivation(self, masterkey, salt=os.urandom(32), iterations=100000): kdf = PBKDF2HMAC(algorithm=hashes.SHA512(), length=32, salt=salt, iterations=iterations, backend=default_backend()) return kdf.derive(masterkey), salt """ HMAC - create """ def hmac_update_finalize(self, key, data): if not isinstance(key, bytes): key = key.encode() if not isinstance(data, bytes): data = pickle.dumps(data) h = hmac.HMAC(key, self.hmac_hash(), backend=default_backend()) h.update(data) return h.finalize() """ HMAC - verify """ def hmac_verify(self, key, hmac_data, data): if not isinstance(key, bytes): key = key.encode() if not isinstance(data, bytes): data = pickle.dumps(data) h = hmac.HMAC(key, self.hmac_hash(), backend=default_backend()) h.update(data) return h.verify(hmac_data) """ SECURE LAYER ENCAPSULATION """ def secure_layer_encrypt(self, msg: bytes, sec_data: dict): # the nounce has been already generated by the client # the iterations number will be the number of requests received by the server for that client # the number that counts is the decrypt number key, salt = self.key_derivation(masterkey=self.session_key, salt=sec_data["salt"], iterations=sec_data["iterations"]) # HMAC hmac_key = sha256(key).hexdigest() hmac_data = self.hmac_update_finalize(hmac_key, msg) pickle_dumps = pickle.dumps([msg, hmac_data]) iv, ciphered_msg = self.sym_cipher(pickle_dumps, ks=key, mode=self.mode) sec_data = pickle.dumps({ "nounce": sec_data["nounce"], "seq": sec_data["seq"], "iv": iv }) # sec_data ciphered sec_data_ciphered = self.hybrid_cipher(sec_data, self.client_public_key) return_message = { "data": base64.b64encode(ciphered_msg).decode(), "sec_data": base64.b64encode(sec_data_ciphered).decode() } # dump the return message pickle_dumps = pickle.dumps(return_message) return base64.b64encode(pickle_dumps) def secure_layer_decrypt(self, msg: bytes): msg = pickle.loads(base64.b64decode(msg)) data = msg["data"].encode() sec_data = base64.b64decode(msg["sec_data"]) iterations = self.requests_received self.requests_received += 1 # decipher the sec_data sec_data = pickle.loads( self.hybrid_decipher(sec_data, self.server_priv_key)) salt = sec_data["salt"] nounce = sec_data["nounce"] iv = sec_data["iv"] key, salt = self.key_derivation(self.session_key, iterations=iterations, salt=salt) raw_msg = pickle.loads( self.sym_decipher(base64.b64decode(data), key, iv, self.mode)) # verify hmac hmac_key = sha256(key).hexdigest() self.hmac_verify(hmac_key, raw_msg[1], raw_msg[0]) data = { "nounce": nounce, "salt": salt, "iterations": iterations, "seq": sec_data["seq"] + 1 } return raw_msg[0], data """ CLIENT SERVER SESSION KEY NEGOTIATION """ def negotiate_session_key(self, phase, val=None): """ First the Application loads the server public key that is distributed into the client application. It's ok to publicly distribute the Public Key but it must be verified if the public key of the server is still the same. If not, it must be updated. Another way is to request the public key of the server and ask for the user fingerprint verification. {verification missing} After that, the client app generate DH values (private and public) to exchange with the server in order to get the shared secret session key. Phase 1: [CLIENT]: send generated DH public key to the server (signed) and the app client rsa public key (signed too). The sent values will be ciphered with a random key and signed. Phase 2: [SERVER]: the server generates the private and public DH pair. Then using the server private key, the server decipher the DH public received encrypted value. Using again the server private key, the server deciphers the client public key and loads it into memory. Then, using the client public key, validates the signature made for the DH public value and public key received. Using the received client public key, the server will make a hybrid cipher (AES and RSA) of the DH server generated values. After the cipher, the server will sign with the server private key the data ciphered. Phase 3: [CLIENT]: using the stored server public key the client will validate the signature received. After that using the client private key, the client will decipher the DH public value received from the server. Then using the DH public value, the client will generate the DH shared secret and using PBKDF2HMAC will use a key derivation function. The master key will be the secret DH shared value and will have 100 000 iterations. The salt is random and so, it will be ciphered and sent to the server. The session key has been generated. Phase 4: [SERVER]: Using the client public key it will be verified the signature of the received value. Using the server private key and a hybrid cipher the PBKDF2 salt will be deciphered. Using the key derivation function the session key will be retrieved in the server. Then, there is a secure channel between the server and the client. :param phase: negotiation phase :param val: value sent by the client :return: value to send to the client """ if phase == 2: # server generate DH private and public key, 1024 para cima ou curva elipticas self.server_dh = DiffieHellman(key_length=256) self.server_dh.generate_public_key() # get mode if val["mode"] == "CTR": self.mode = modes.CTR elif val["mode"] == "CFB": self.mode = modes.CFB elif val["mode"] == "OFB": self.mode = modes.OFB else: print("Wrong input!") exit(1) if val["hmac_hash"] == "sha256": self.hmac_hash = hashes.SHA256 elif val["hmac_hash"] == "sha512": self.hmac_hash = hashes.SHA512 # decipher the received DH value client_dh_pub = self.hybrid_decipher(val["data"], self.server_priv_key) # decipher client public key PEM format client_public_key_pem = self.hybrid_decipher( val["public_key"], self.server_priv_key) # load the client public key self.client_public_key = serialization.load_pem_public_key( client_public_key_pem, backend=default_backend()) # validate signed data [data = dh value] self.asym_validate_sign( val["data"].encode(), base64.b64decode(val["data_signature"].encode()), self.client_public_key) # validate signature of client public key self.asym_validate_sign( val["public_key"].encode(), base64.b64decode(val["public_key_signature"].encode()), self.client_public_key) # cipher the server DH public key with the client public key server_dh_ciphered = self.hybrid_cipher(self.server_dh.public_key, self.client_public_key) # generate the DH shared secret (client session key) self.server_dh.generate_shared_secret(client_dh_pub) return { "data": server_dh_ciphered.decode(), "data_signature": base64.b64encode( self.asym_sign(self.server_priv_key, server_dh_ciphered)).decode(), "phase": 3 } elif phase == 4: # validate signature of the received salt self.asym_validate_sign( val["data"].encode(), base64.b64decode(val["data_signature"].encode()), self.client_public_key) # decipher the salt for PBKDF2 pbkdf2_salt = self.hybrid_decipher(val["data"], self.server_priv_key) # save the session key self.session_key, salt = self.key_derivation( str(self.server_dh.shared_secret).encode(), pbkdf2_salt)