def send_client(self, flag): """ Handles the sending feature to the respective clients that are connected to the Broker @param flag: <str> Requested flag to be performed @return: No return """ # Load the RSA Cipher self.rsa_cipher = RSACipher() # Encryption list for temporary storage enc = [] recipient_df = CLIENT_DF.loc[CLIENT_DF['id'] == self.request] client_sess, client_name, pubkey = recipient_df.values[0] client_pubkey = self.rsa_cipher.importRSAKey(pubkey) if flag == ZONE_FILE: logging.info(f"Sending Zone file to {client_name}") # Open and read the zone file bye by byte with open(ZONE_DB_DIR, "rb") as in_file: while (byte := in_file.read(1)): # Encrypt the Zone file with RSA Cipher ciphertext = self.rsa_cipher.encrypt_with_RSA( pub_key=client_pubkey, data=byte) enc.append(ciphertext) # Serialize the encrypted data and send to the client msg = (enc, blockchain.chain) client_sess.sendall(pickle.dumps(msg)) # Send Zone File flag to indicate EOL client_sess.sendall(ZONE_FILE) # Reset the encryption list enc = []
def get_pubkey(pubkey_dir): """ Function to get Public Key of Alice @param pubkey_dir: <str> Directory of the client's Public Key @return: """ rsa_cipher = RSACipher() return rsa_cipher.load_pubkey(pubkey_dir).publickey().exportKey( format='PEM', passphrase=None, pkcs=1)
def message_handle(self): """ Handles the message between server and client """ # Load the RSACipher for encryption/decryption self.rsa_cipher = RSACipher() privkey = self.rsa_cipher.load_privkey(SECRET_KEY) try: # Prepare for incoming data data = b"" while True: packet = self.client_sock.recv(BUFSIZE) # Break out of the loop the connection is lost to the server if not packet: break elif CONSENSUS in packet: # Strip the flag data += packet.rstrip(CONSENSUS) # Load the encrypted data list chain = pickle.loads(data) # Reset the data buffer data, packet = b"", b"" # Verify the given blockchain if self.blockchain.verify_blockchain(chain): # Update the client Blockchain self.blockchain.chain = chain # ZONE FILE HANDLER elif ZONE_FILE in packet: # Strip the flag data += packet.rstrip(ZONE_FILE) # Load the encrypted data list enc, chain = pickle.loads(data) # Reset the data buffer data, packet = b"", b"" # Prepare to write zone file contents locally and stored in client/ folder print( f"[+] Zone file received from Broker, saving under: {DEFAULT_ZONE_FILE}" ) with open(DEFAULT_ZONE_FILE, "wb") as out_file: for ciphertext in enc: plaintext = self.rsa_cipher.decrypt_with_RSA( privkey, ciphertext) out_file.write(plaintext) # Verify the given blockchain if self.blockchain.verify_blockchain(chain): # Update the client Blockchain self.blockchain.chain = chain # Run the user_menu threading.Thread(target=self.user_menu).start() # NEW DOMAIN File Handler elif NEW_DOMAIN in packet: print("[+] Receiving a new domain zone file") # Strip the flag data += packet.rstrip(NEW_DOMAIN) # Load the encrypted data into a dictionary new_domain = json.loads( self.rsa_cipher.decrypt_with_RSA(priv_key=privkey, data=data)) # Reset the data buffer data, packet = b"", b"" # Extract the domain_name domain_name = list(new_domain.keys())[0] new_domain_zone_fpath = f"client/{UUID}/{domain_name}.json" print( f"[+] Writing new zone file: {domain_name} to {new_domain_zone_fpath}" ) # Save the new domain zone file locally with open(new_domain_zone_fpath, "w") as out_file: out_file.write(json.dumps(new_domain)) # Concatenate the data data += packet except KeyboardInterrupt: self.client_sock.close() except socket.error: self.client_sock.close()
class Client(object): def __init__(self, host, port): """ Initial Connection to the Broker Address @param host: <str> IP Addr of the Broker @param port: <int> Port number of the Broker @return: <sock> Client socket connection to the Broker """ print(f"[*] Connecting to Broker @ ({host},{port})") # Start the blockchain self.blockchain = Blockchain() # Initialise socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: self.client_sock = sock # Connects to broker try: self.client_sock.connect((host, port)) except socket.error: print( "[!] Connection failed! Please check your network connectivity and try again." ) self.client_sock.close() # Send client pubkey over to server on initial connection server_hello_msg = (UUID, self.get_pubkey(CLIENT_PUBKEY_DIR)) self.client_sock.sendall(pickle.dumps(server_hello_msg)) # Run the message_handle self.message_handle() def message_handle(self): """ Handles the message between server and client """ # Load the RSACipher for encryption/decryption self.rsa_cipher = RSACipher() privkey = self.rsa_cipher.load_privkey(SECRET_KEY) try: # Prepare for incoming data data = b"" while True: packet = self.client_sock.recv(BUFSIZE) # Break out of the loop the connection is lost to the server if not packet: break elif CONSENSUS in packet: # Strip the flag data += packet.rstrip(CONSENSUS) # Load the encrypted data list chain = pickle.loads(data) # Reset the data buffer data, packet = b"", b"" # Verify the given blockchain if self.blockchain.verify_blockchain(chain): # Update the client Blockchain self.blockchain.chain = chain # ZONE FILE HANDLER elif ZONE_FILE in packet: # Strip the flag data += packet.rstrip(ZONE_FILE) # Load the encrypted data list enc, chain = pickle.loads(data) # Reset the data buffer data, packet = b"", b"" # Prepare to write zone file contents locally and stored in client/ folder print( f"[+] Zone file received from Broker, saving under: {DEFAULT_ZONE_FILE}" ) with open(DEFAULT_ZONE_FILE, "wb") as out_file: for ciphertext in enc: plaintext = self.rsa_cipher.decrypt_with_RSA( privkey, ciphertext) out_file.write(plaintext) # Verify the given blockchain if self.blockchain.verify_blockchain(chain): # Update the client Blockchain self.blockchain.chain = chain # Run the user_menu threading.Thread(target=self.user_menu).start() # NEW DOMAIN File Handler elif NEW_DOMAIN in packet: print("[+] Receiving a new domain zone file") # Strip the flag data += packet.rstrip(NEW_DOMAIN) # Load the encrypted data into a dictionary new_domain = json.loads( self.rsa_cipher.decrypt_with_RSA(priv_key=privkey, data=data)) # Reset the data buffer data, packet = b"", b"" # Extract the domain_name domain_name = list(new_domain.keys())[0] new_domain_zone_fpath = f"client/{UUID}/{domain_name}.json" print( f"[+] Writing new zone file: {domain_name} to {new_domain_zone_fpath}" ) # Save the new domain zone file locally with open(new_domain_zone_fpath, "w") as out_file: out_file.write(json.dumps(new_domain)) # Concatenate the data data += packet except KeyboardInterrupt: self.client_sock.close() except socket.error: self.client_sock.close() def send_server(self, flag): """ Constructs and forward data over to the broker """ pubkey = self.rsa_cipher.load_pubkey(BROKER_PUBKEY_DIR) enc = [] if flag == REGIS_DOMAIN: with open(self.new_zone_fpath, "rb") as in_file: while (byte := in_file.read(1)): ciphertext = self.rsa_cipher.encrypt_with_RSA( pub_key=pubkey, data=byte) enc.append(ciphertext) print( "[+] Forwarding new zone file and transaction block to Broker ..." ) # Serialize the encrypted data and send to the client msg = (enc, self.blockchain.current_transactions) self.client_sock.sendall(pickle.dumps(msg)) # Send REGIS_DOMAIN flag to indicate EOL self.client_sock.sendall(REGIS_DOMAIN) enc, self.blockchain.current_transactions = [], [] elif flag == CONSENSUS: print("[+] Sending request for update to Broker ...") # Send CONSENSUS flag to indicate update request self.client_sock.sendall(CONSENSUS)
class ThreadedServerHandle(socketserver.BaseRequestHandler): def handle(self): global CLIENT_DF # Try catch the error try: # Get the user_id and public key user_id, user_pubkey = pickle.loads(self.request.recv(BUFSIZE)) self.username = self.get_username(USER_DB_DIR, user_id) # Info message logging.info(f"{self.username} has started the connection.") # Add the new Client to the session DB CLIENT_DF = CLIENT_DF.append( { "id": self.request, "client_name": self.username, "pubkey": user_pubkey }, ignore_index=True) # Write Active Clients to Log File with open(CLIENT_SESS_LOG, "w+") as out_file: out_file.write(CLIENT_DF['client_name'].str.cat(sep=',')) # Check for the logon username if self.username == "miner": # Send previous hash to miner self.send_miner() else: # Send Zone File to the client self.send_client(ZONE_FILE) # Run the message handler to receive client data self.message_handle() # Close the socket if client forcefully close the connection except socket.error: self.request.close() def send_client(self, flag): """ Handles the sending feature to the respective clients that are connected to the Broker @param flag: <str> Requested flag to be performed @return: No return """ # Load the RSA Cipher self.rsa_cipher = RSACipher() # Encryption list for temporary storage enc = [] recipient_df = CLIENT_DF.loc[CLIENT_DF['id'] == self.request] client_sess, client_name, pubkey = recipient_df.values[0] client_pubkey = self.rsa_cipher.importRSAKey(pubkey) if flag == ZONE_FILE: logging.info(f"Sending Zone file to {client_name}") # Open and read the zone file bye by byte with open(ZONE_DB_DIR, "rb") as in_file: while (byte := in_file.read(1)): # Encrypt the Zone file with RSA Cipher ciphertext = self.rsa_cipher.encrypt_with_RSA( pub_key=client_pubkey, data=byte) enc.append(ciphertext) # Serialize the encrypted data and send to the client msg = (enc, blockchain.chain) client_sess.sendall(pickle.dumps(msg)) # Send Zone File flag to indicate EOL client_sess.sendall(ZONE_FILE) # Reset the encryption list enc = [] elif flag == CONSENSUS: logging.info(f"Client {client_name} request for Consensus") # Send the Block Chain to Client client_sess.sendall(pickle.dumps(blockchain.chain)) # Send CONSENSUS flag to indicate EOL client_sess.sendall(CONSENSUS)