def _parse_initial_node_table(initial_node_table: bfcp_pb2.NodeTable)\ -> Dict[bytes, bfcp_pb2.NodeTableEntry]: result = RandomDict() for entry in initial_node_table.entries: pub_key = proto_to_pubkey(entry.node.public_key) result[pubkey_to_deterministic_string(pub_key)] = entry return result
async def on_end_node_found(self, conn_resp: bfcp_pb2.ConnectionResponse): if self._tcp_state is not None: return # Verify the challenge end_node_key = proto_to_pubkey(conn_resp.selected_end_node.public_key) pkcs1_15.new(end_node_key).verify( SHA256.new(self._challenge_bytes), conn_resp.signature_challenge_response) rsa_cipher = PKCS1_OAEP.new(self._sender_connection_key) self._session_key = rsa_cipher.decrypt(conn_resp.session_key.key) # Start the TCP channel self._tcp_state = BouncyTcpTrafficHandler(self._session_key) # Found an EN, now try to establish channels for i in range(GLOBAL_VARS['CHANNELS_PER_CONNECTION']): channel_uuid = str(uuid4()) channel_request = bfcp_pb2.ChannelRequest() channel_request.end_node.CopyFrom(conn_resp.selected_end_node) channel_request.channel_uuid = channel_uuid channel_request.connection_params.uuid = self.uuid channel_request.connection_params.remaining_hops = self._make_channel_length( ) await self._traffic_manager.send(channel_request)
async def on_channel_request(self, msg: bfcp_pb2.ChannelRequest, sender_key: RsaKey): channel_id = bfcp_pb2.ChannelID() channel_id.connection_uuid = msg.connection_params.uuid channel_id.channel_uuid = msg.channel_uuid channel_type = self._check_channel_type(channel_id) print('OnChannelRequest', channel_type) if channel_type == ConnectionType.end: # I am the end node self._en_conn[msg.connection_params.uuid][1].append( (msg.channel_uuid, sender_key)) response = bfcp_pb2.ChannelResponse() response.channel_id.CopyFrom(channel_id) await self._traffic_manager.send(response, sender_key) else: msg.connection_params.remaining_hops -= 1 next_node = self._trust_table.get_random_node().node \ if msg.connection_params.remaining_hops > 0 else msg.end_node if channel_type == ConnectionType.neither: # This is a new ChannelRequest, forward it self._relay_channels[((channel_id.connection_uuid, channel_id.channel_uuid))] = ( sender_key, proto_to_pubkey( next_node.public_key)) elif channel_type == ConnectionType.relay: # This request was here already. Remove the cycle (prev_node, _) = self._relay_channels[(channel_id.connection_uuid, channel_id.channel_uuid)] self._relay_channels[(channel_id.connection_uuid, channel_id.channel_uuid)] = ( prev_node, proto_to_pubkey( next_node.public_key)) else: # This is the original sender, no relaying needed pass await self._traffic_manager.send( msg, proto_to_pubkey(next_node.public_key))
async def _become_end_node(self, conn_request: bfcp_pb2.ConnectionRequest, sender_key: RsaKey): """ Respond to a ConnectionRequest, saying that "I'll be the end node". And prepare to be one. """ # solve the challenge h = SHA256.new(conn_request.signature_challenge) solved_challenge = pkcs1_15.new(self._bfc_node.rsa_key).sign(h) conn_resp = bfcp_pb2.ConnectionResponse() conn_resp.uuid = conn_request.connection_params.uuid conn_resp.selected_end_node.public_key.CopyFrom( pubkey_to_proto(self._bfc_node.rsa_key.publickey())) conn_resp.selected_end_node.last_known_address = self._bfc_node.host[0] conn_resp.selected_end_node.last_port = self._bfc_node.host[1] conn_resp.signature_challenge_response = solved_challenge # Prepare the session key session_key = utils.generate_aes_key(GLOBAL_VARS['OS_EN_KEY_SIZE']) original_sender_pub_key = proto_to_pubkey( conn_request.sender_connection_key) cipher_rsa = PKCS1_OAEP.new(original_sender_pub_key) encrypted_session_key = cipher_rsa.encrypt(session_key) conn_resp.session_key.key = encrypted_session_key # TODO: prev hops and en_conn are bound. This is quite nasty and hard to read. prev_hops = [] en_conn = EndNodeConnection(self._traffic_manager, conn_request.connection_params.uuid, prev_hops, session_key) self._en_conn[conn_request.connection_params.uuid] = (en_conn, prev_hops) await self._traffic_manager.send(conn_resp, sender_key) ensure_future( en_conn.initiate_connection((conn_request.target_server_address, conn_request.target_server_port)))
def test_pub_key_encoding(self): key = RSA.generate(1024).publickey() self.assertEqual(protocol.proto_to_pubkey(protocol.pubkey_to_proto(key)), key)