def deserialize_private_key(data: bytes) -> PrivateKey: f = PrivateKey.deserialize_from_protobuf(data) try: deserializer = key_type_to_private_key_deserializer[f.key_type] except KeyError: raise MissingDeserializerError({"key_type": f.key_type, "key": "private_key"}) return deserializer(f.data)
def add_privkey(self, peer_id: ID, privkey: PrivateKey) -> None: """ :param peer_id: peer ID to add private key for :param privkey: :raise PeerStoreError: if peer ID or peer privkey not found """ peer_data = self.peer_data_map[peer_id] if ID.from_pubkey(privkey.get_public_key()) != peer_id: raise PeerStoreError("peer ID and privkey does not match") peer_data.add_privkey(privkey)
async def _establish_session_parameters( local_peer: PeerID, local_private_key: PrivateKey, remote_peer: Optional[PeerID], conn: MsgIOReadWriter, nonce: bytes, ) -> Tuple[SessionParameters, bytes]: # establish shared encryption parameters session_parameters = SessionParameters() session_parameters.local_peer = local_peer local_encryption_parameters = EncryptionParameters() session_parameters.local_encryption_parameters = local_encryption_parameters local_public_key = local_private_key.get_public_key() local_encryption_parameters.permanent_public_key = local_public_key local_proposal = Proposal(nonce, local_public_key) serialized_local_proposal = local_proposal.serialize() serialized_remote_proposal = await _response_to_msg( conn, serialized_local_proposal) remote_encryption_parameters = EncryptionParameters() session_parameters.remote_encryption_parameters = remote_encryption_parameters remote_proposal = Proposal.deserialize(serialized_remote_proposal) remote_encryption_parameters.permanent_public_key = remote_proposal.public_key remote_peer_from_proposal = remote_proposal.calculate_peer_id() if not remote_peer: remote_peer = remote_peer_from_proposal elif remote_peer != remote_peer_from_proposal: raise PeerMismatchException({ "expected_remote_peer": remote_peer, "received_remote_peer": remote_peer_from_proposal, }) session_parameters.remote_peer = remote_peer curve_param, cipher_param, hash_param, order = _select_encryption_parameters( local_proposal, remote_proposal) local_encryption_parameters.curve_type = curve_param local_encryption_parameters.cipher_type = cipher_param local_encryption_parameters.hash_type = hash_param remote_encryption_parameters.curve_type = curve_param remote_encryption_parameters.cipher_type = cipher_param remote_encryption_parameters.hash_type = hash_param session_parameters.order = order # exchange ephemeral pub keys local_ephemeral_public_key, shared_key_generator = create_ephemeral_key_pair( curve_param) local_encryption_parameters.ephemeral_public_key = local_ephemeral_public_key local_selection = (serialized_local_proposal + serialized_remote_proposal + local_ephemeral_public_key.to_bytes()) exchange_signature = local_private_key.sign(local_selection) local_exchange = Exchange( ephemeral_public_key=local_ephemeral_public_key.to_bytes(), signature=exchange_signature, ) serialized_local_exchange = local_exchange.SerializeToString() serialized_remote_exchange = await _response_to_msg( conn, serialized_local_exchange) remote_exchange = Exchange() remote_exchange.ParseFromString(serialized_remote_exchange) remote_ephemeral_public_key_bytes = remote_exchange.ephemeral_public_key remote_ephemeral_public_key = ECCPublicKey.from_bytes( remote_ephemeral_public_key_bytes, curve_param) remote_encryption_parameters.ephemeral_public_key = remote_ephemeral_public_key remote_selection = (serialized_remote_proposal + serialized_local_proposal + remote_ephemeral_public_key_bytes) valid_signature = remote_encryption_parameters.permanent_public_key.verify( remote_selection, remote_exchange.signature) if not valid_signature: raise InvalidSignatureOnExchange() shared_key = shared_key_generator(remote_ephemeral_public_key_bytes) session_parameters.shared_key = shared_key return session_parameters, remote_proposal.nonce
async def run_handshake( local_peer: ID, local_private_key: PrivateKey, conn: IRawConnection, is_initiator: bool, remote_peer_id: ID, ) -> ISecureConn: """Raise `HandshakeFailure` when handshake failed.""" msg = make_exchange_message(local_private_key.get_public_key()) msg_bytes = msg.SerializeToString() read_writer = PlaintextHandshakeReadWriter(conn) try: await read_writer.write_msg(msg_bytes) except RawConnError as e: raise HandshakeFailure("connection closed") from e try: remote_msg_bytes = await read_writer.read_msg() except RawConnError as e: raise HandshakeFailure("connection closed") from e remote_msg = plaintext_pb2.Exchange() remote_msg.ParseFromString(remote_msg_bytes) received_peer_id = ID(remote_msg.id) # Verify if the receive `ID` matches the one we originally initialize the session. # We only need to check it when we are the initiator, because only in that condition # we possibly knows the `ID` of the remote. if is_initiator and remote_peer_id != received_peer_id: raise HandshakeFailure( "remote peer sent unexpected peer ID. " f"expected={remote_peer_id} received={received_peer_id}" ) # Verify if the given `pubkey` matches the given `peer_id` try: received_pubkey = deserialize_public_key(remote_msg.pubkey.SerializeToString()) except ValueError as e: raise HandshakeFailure( f"unknown `key_type` of remote_msg.pubkey={remote_msg.pubkey}" ) from e except MissingDeserializerError as error: raise HandshakeFailure() from error peer_id_from_received_pubkey = ID.from_pubkey(received_pubkey) if peer_id_from_received_pubkey != received_peer_id: raise HandshakeFailure( "peer id and pubkey from the remote mismatch: " f"received_peer_id={received_peer_id}, remote_pubkey={received_pubkey}, " f"peer_id_from_received_pubkey={peer_id_from_received_pubkey}" ) secure_conn = InsecureSession( local_peer=local_peer, local_private_key=local_private_key, remote_peer=received_peer_id, remote_permanent_pubkey=received_pubkey, is_initiator=is_initiator, conn=conn, ) # TODO: Store `pubkey` and `peer_id` to `PeerStore` return secure_conn
def make_handshake_payload_sig(id_privkey: PrivateKey, noise_static_pubkey: PublicKey) -> bytes: data = make_data_to_be_signed(noise_static_pubkey) return id_privkey.sign(data)
def deserialize_private_key(data: bytes) -> PrivateKey: f = PrivateKey.deserialize_from_protobuf(data) deserializer = key_type_to_private_key_deserializer[f.key_type] return deserializer(f.data)