Пример #1
0
 def verify_signature(self, alice_pubkey: 'UmbralPublicKey'):
     """
     Verifies the revocation was from the provided pubkey.
     """
     if not self.signature.verify(self.prefix + self.arrangement_id, alice_pubkey):
         raise InvalidSignature(
             "Revocation has an invalid signature: {}".format(self.signature))
     return True
Пример #2
0
    def set_policy(id_as_hex):
        """
        REST endpoint for setting a kFrag.
        """
        policy_message_kit = UmbralMessageKit.from_bytes(request.data)

        alices_verifying_key = policy_message_kit.sender_verifying_key
        alice = _alice_class.from_public_keys(
            verifying_key=alices_verifying_key)

        try:
            cleartext = this_node.verify_from(alice,
                                              policy_message_kit,
                                              decrypt=True)
        except InvalidSignature:
            # TODO: Perhaps we log this?  Essentially 355.
            return Response(status_code=400)

        if not this_node.federated_only:
            # This splitter probably belongs somewhere canonical.
            transaction_splitter = BytestringSplitter(32)
            tx, kfrag_bytes = transaction_splitter(cleartext,
                                                   return_remainder=True)

            try:
                # Get all of the arrangements and verify that we'll be paid.
                # TODO: We'd love for this part to be impossible to reduce the risk of collusion.  #1274
                arranged_addresses = this_node.policy_agent.fetch_arrangement_addresses_from_policy_txid(
                    tx, timeout=this_node.synchronous_query_timeout)
            except TimeExhausted:
                # Alice didn't pay.  Return response with that weird status code.
                this_node.suspicious_activities_witnessed['freeriders'].append(
                    (alice, f"No transaction matching {tx}."))
                return Response(status=402)

            this_node_has_been_arranged = this_node.checksum_address in arranged_addresses
            if not this_node_has_been_arranged:
                this_node.suspicious_activities_witnessed['freeriders'].append(
                    (alice,
                     f"The transaction {tx} does not list me as a Worker - it lists {arranged_addresses}."
                     ))
                return Response(status=402)
        else:
            _tx = NO_BLOCKCHAIN_CONNECTION
            kfrag_bytes = cleartext
        kfrag = KFrag.from_bytes(kfrag_bytes)

        if not kfrag.verify(signing_pubkey=alices_verifying_key):
            raise InvalidSignature("{} is invalid".format(kfrag))

        with ThreadedSession(db_engine) as session:
            datastore.attach_kfrag_to_saved_arrangement(alice,
                                                        id_as_hex,
                                                        kfrag,
                                                        session=session)

        # TODO: Sign the arrangement here.  #495
        return ""  # TODO: Return A 200, with whatever policy metadata.
Пример #3
0
    def reencrypt_via_rest(id_as_hex):
        from nucypher.policy.models import WorkOrder  # Avoid circular import
        arrangement_id = binascii.unhexlify(id_as_hex)
        work_order = WorkOrder.from_rest_payload(arrangement_id, request.data)
        log.info("Work Order from {}, signed {}".format(
            work_order.bob, work_order.receipt_signature))
        with ThreadedSession(db_engine) as session:
            policy_arrangement = datastore.get_policy_arrangement(
                arrangement_id=id_as_hex.encode(), session=session)
        kfrag_bytes = policy_arrangement.kfrag  # Careful!  :-)
        verifying_key_bytes = policy_arrangement.alice_pubkey_sig.key_data

        # TODO: Push this to a lower level. Perhaps to Ursula character? #619
        kfrag = KFrag.from_bytes(kfrag_bytes)
        alices_verifying_key = UmbralPublicKey.from_bytes(verifying_key_bytes)
        cfrag_byte_stream = b""

        alices_address = canonical_address_from_umbral_key(
            alices_verifying_key)
        if not alices_address == work_order.alice_address:
            message = f"This Bob ({work_order.bob}) sent an Alice's ETH address " \
                      f"({work_order.alice_address}) that doesn't match " \
                      f"the one I have ({alices_address})."
            raise SuspiciousActivity(message)

        bob_pubkey = work_order.bob.stamp.as_umbral_pubkey()
        if not work_order.alice_address_signature.verify(
                message=alices_address, verifying_key=bob_pubkey):
            message = f"This Bob ({work_order.bob}) sent an invalid signature of Alice's ETH address"
            raise InvalidSignature(message)

        # This is Bob's signature of Alice's verifying key as ETH address.
        alice_address_signature = bytes(work_order.alice_address_signature)

        for capsule, capsule_signature in zip(work_order.capsules,
                                              work_order.capsule_signatures):
            # This is the capsule signed by Bob
            capsule_signature = bytes(capsule_signature)
            # Ursula signs on top of it. Now both are committed to the same capsule.
            # She signs Alice's address too.
            ursula_signature = stamp(capsule_signature +
                                     alice_address_signature)
            capsule.set_correctness_keys(verifying=alices_verifying_key)
            cfrag = pre.reencrypt(kfrag,
                                  capsule,
                                  metadata=bytes(ursula_signature))
            log.info(f"Re-encrypting for {capsule}, made {cfrag}.")
            signature = stamp(bytes(cfrag) + bytes(capsule))
            cfrag_byte_stream += VariableLengthBytestring(cfrag) + signature

        # TODO: Put this in Ursula's datastore
        work_order_tracker.append(work_order)

        headers = {'Content-Type': 'application/octet-stream'}

        return Response(response=cfrag_byte_stream, headers=headers)
Пример #4
0
    def from_rest_payload(cls, arrangement_id, rest_payload, ursula,
                          alice_address):

        payload_splitter = BytestringSplitter(Signature) + key_splitter
        payload_elements = payload_splitter(rest_payload,
                                            msgpack_remainder=True)

        signature, bob_verifying_key, (tasks_bytes,
                                       blockhash) = payload_elements

        # TODO: check freshness of blockhash?

        ursula_identity_evidence = b''
        if ursula._stamp_has_valid_signature_by_worker():
            ursula_identity_evidence = ursula.decentralized_identity_evidence

        tasks = []
        for task_bytes in tasks_bytes:
            task = cls.PRETask.from_bytes(task_bytes)
            tasks.append(task)

            # Each task signature has to match the original specification
            specification = task.get_specification(ursula.stamp, alice_address,
                                                   blockhash,
                                                   ursula_identity_evidence)

            if not task.signature.verify(specification, bob_verifying_key):
                raise InvalidSignature()

        # Check receipt
        receipt_bytes = b"wo:" + bytes(ursula.stamp) + keccak_digest(
            *[bytes(task.capsule) for task in tasks])
        if not signature.verify(receipt_bytes, bob_verifying_key):
            raise InvalidSignature()

        bob = Bob.from_public_keys(verifying_key=bob_verifying_key)
        return cls(bob=bob,
                   ursula=ursula,
                   arrangement_id=arrangement_id,
                   tasks=tasks,
                   alice_address=alice_address,
                   blockhash=blockhash,
                   receipt_signature=signature)
Пример #5
0
    def from_rest_payload(cls, arrangement_id, rest_payload, ursula,
                          alice_address):

        payload_splitter = BytestringSplitter(
            Signature) + key_splitter + BytestringSplitter(
                ETH_HASH_BYTE_LENGTH)

        signature, bob_verifying_key, blockhash, remainder = payload_splitter(
            rest_payload, return_remainder=True)
        tasks = {
            capsule: cls.PRETask(capsule, sig)
            for capsule, sig in cls.PRETask.input_splitter.repeat(remainder)
        }
        # TODO: check freshness of blockhash? #259

        ursula_identity_evidence = b''
        if ursula._stamp_has_valid_signature_by_worker():
            ursula_identity_evidence = ursula.decentralized_identity_evidence

        for task in tasks.values():
            # Each task signature has to match the original specification
            specification = task.get_specification(ursula.stamp, alice_address,
                                                   blockhash,
                                                   ursula_identity_evidence)

            if not task.signature.verify(specification, bob_verifying_key):
                raise InvalidSignature()

        # Check receipt
        capsules = b''.join(map(bytes, tasks.keys()))
        receipt_bytes = cls.HEADER + bytes(ursula.stamp) + capsules
        if not signature.verify(receipt_bytes, bob_verifying_key):
            raise InvalidSignature()

        bob = Bob.from_public_keys(verifying_key=bob_verifying_key)
        return cls(bob=bob,
                   ursula=ursula,
                   arrangement_id=arrangement_id,
                   tasks=tasks,
                   alice_address=alice_address,
                   blockhash=blockhash,
                   receipt_signature=signature)
Пример #6
0
    def from_rest_payload(cls, arrangement_id, rest_payload,
                          ursula_pubkey_bytes, alice_address):

        payload_splitter = BytestringSplitter(Signature) + key_splitter
        payload_elements = payload_splitter(rest_payload,
                                            msgpack_remainder=True)

        signature, bob_verifying_key, (tasks_bytes,
                                       blockhash) = payload_elements

        # TODO: check freshness of blockhash?

        # Check receipt
        receipt_bytes = b"wo:" + ursula_pubkey_bytes + msgpack.dumps(
            tasks_bytes)
        if not signature.verify(receipt_bytes, bob_verifying_key):
            raise InvalidSignature()

        tasks = []
        for task_bytes in tasks_bytes:
            task = cls.Task.from_bytes(task_bytes)
            tasks.append(task)

            # Each task signature has to match the original specification
            specification = task.get_specification(ursula_pubkey_bytes,
                                                   alice_address, blockhash)
            if not task.signature.verify(specification, bob_verifying_key):
                raise InvalidSignature()

        bob = Bob.from_public_keys(verifying_key=bob_verifying_key)
        return cls(bob=bob,
                   arrangement_id=arrangement_id,
                   tasks=tasks,
                   alice_address=alice_address,
                   blockhash=blockhash,
                   receipt_signature=signature)
Пример #7
0
    def complete(self, cfrags_and_signatures):
        good_cfrags = []
        if not len(self) == len(cfrags_and_signatures):
            raise ValueError("Ursula gave back the wrong number of cfrags. She's up to something.")

        ursula_verifying_key = self.ursula.stamp.as_umbral_pubkey()

        for task, (cfrag, cfrag_signature) in zip(self.tasks.values(), cfrags_and_signatures):

            # Validate re-encryption signatures
            if cfrag_signature.verify(ursula_verifying_key, bytes(cfrag)):
                good_cfrags.append(cfrag)
            else:
                raise InvalidSignature(f"{cfrag} is not properly signed by Ursula.")
                # TODO: Instead of raising, we should do something (#957)

        for task, (cfrag, cfrag_signature) in zip(self.tasks.values(), cfrags_and_signatures):
            task.attach_work_result(cfrag, cfrag_signature)

        self.completed = maya.now()
        return good_cfrags
Пример #8
0
    def precompute_values(self) -> bytes:

        umbral_params = default_params()
        e, v, _ = self.capsule.components()

        e1 = self.cfrag.point_e1
        v1 = self.cfrag.point_v1
        e2 = self.cfrag.proof.point_e2
        v2 = self.cfrag.proof.point_v2
        u = umbral_params.u
        u1 = self.cfrag.proof.point_kfrag_commitment
        u2 = self.cfrag.proof.point_kfrag_pok

        h = self.get_proof_challenge_scalar()

        e1h = h * e1
        v1h = h * v1
        u1h = h * u1

        z = self.cfrag.proof.bn_sig
        ez = z * e
        vz = z * v
        uz = z * u

        def raw_bytes_from_point(point: Point, only_y_coord=False) -> bytes:
            uncompressed_point_bytes = point.to_bytes(is_compressed=False)
            if only_y_coord:
                y_coord_start = (1 + Point.expected_bytes_length(is_compressed=False)) // 2
                return uncompressed_point_bytes[y_coord_start:]
            else:
                return uncompressed_point_bytes[1:]

        # E points
        e_y = raw_bytes_from_point(e, only_y_coord=True)
        ez_xy = raw_bytes_from_point(ez)
        e1_y = raw_bytes_from_point(e1, only_y_coord=True)
        e1h_xy = raw_bytes_from_point(e1h)
        e2_y = raw_bytes_from_point(e2, only_y_coord=True)
        # V points
        v_y = raw_bytes_from_point(v, only_y_coord=True)
        vz_xy = raw_bytes_from_point(vz)
        v1_y = raw_bytes_from_point(v1, only_y_coord=True)
        v1h_xy = raw_bytes_from_point(v1h)
        v2_y = raw_bytes_from_point(v2, only_y_coord=True)
        # U points
        uz_xy = raw_bytes_from_point(uz)
        u1_y = raw_bytes_from_point(u1, only_y_coord=True)
        u1h_xy = raw_bytes_from_point(u1h)
        u2_y = raw_bytes_from_point(u2, only_y_coord=True)

        # Get hashed KFrag validity message
        hash_function = hashes.Hash(hashes.SHA256(), backend=backend)

        kfrag_id = self.cfrag.kfrag_id
        precursor = self.cfrag.point_precursor
        delegating_pubkey = self.delegating_pubkey
        receiving_pubkey = self.receiving_pubkey

        validity_input = (kfrag_id, delegating_pubkey, receiving_pubkey, u1, precursor)
        kfrag_validity_message = bytes().join(bytes(item) for item in validity_input)
        hash_function.update(kfrag_validity_message)
        hashed_kfrag_validity_message = hash_function.finalize()

        # Get Alice's verifying pubkey as ETH address
        alice_address = canonical_address_from_umbral_key(self.verifying_pubkey)

        # Get KFrag signature's v value
        v_value = 27
        pubkey_bytes = recover_pubkey_from_signature(prehashed_message=hashed_kfrag_validity_message,
                                                     signature=self.cfrag.proof.kfrag_signature,
                                                     v_value_to_try=v_value)
        if not pubkey_bytes == self.verifying_pubkey.to_bytes():
            v_value = 28
            pubkey_bytes = recover_pubkey_from_signature(prehashed_message=hashed_kfrag_validity_message,
                                                         signature=self.cfrag.proof.kfrag_signature,
                                                         v_value_to_try=v_value)
        if not pubkey_bytes == self.verifying_pubkey.to_bytes():
            raise InvalidSignature("Bad signature: Not possible to recover public key from it.")

        # Bundle everything together
        pieces = (
            e_y, ez_xy, e1_y, e1h_xy, e2_y,
            v_y, vz_xy, v1_y, v1h_xy, v2_y,
            uz_xy, u1_y, u1h_xy, u2_y,
            hashed_kfrag_validity_message,
            alice_address,
            v_value.to_bytes(1, 'big'),
        )
        return b''.join(pieces)