Beispiel #1
0
    def reencrypt_via_rest(id_as_hex):
        from nucypher.policy.collections import WorkOrder  # Avoid circular import
        arrangement_id = binascii.unhexlify(id_as_hex)
        try:
            with ThreadedSession(db_engine) as session:
                policy_arrangement = datastore.get_policy_arrangement(
                    arrangement_id=id_as_hex.encode(), session=session)
        except NotFound:
            return Response(response=arrangement_id, status=404)
        kfrag_bytes = policy_arrangement.kfrag  # Careful!  :-)
        verifying_key_bytes = policy_arrangement.alice_verifying_key.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)
        alices_address = canonical_address_from_umbral_key(
            alices_verifying_key)

        work_order = WorkOrder.from_rest_payload(arrangement_id=arrangement_id,
                                                 rest_payload=request.data,
                                                 ursula=this_node,
                                                 alice_address=alices_address)

        log.info(
            f"Work Order from {work_order.bob}, signed {work_order.receipt_signature}"
        )

        cfrag_byte_stream = b""

        for task in work_order.tasks:
            # Ursula signs on top of Bob's signature of each task.
            # Now both are committed to the same task.  See #259.
            reencryption_metadata = bytes(
                this_node.stamp(bytes(task.signature)))

            capsule = task.capsule
            capsule.set_correctness_keys(verifying=alices_verifying_key)
            cfrag = pre.reencrypt(kfrag,
                                  capsule,
                                  metadata=reencryption_metadata)
            log.info(f"Re-encrypting for {capsule}, made {cfrag}.")

            # Finally, Ursula commits to her result
            reencryption_signature = this_node.stamp(bytes(cfrag))
            cfrag_byte_stream += VariableLengthBytestring(
                cfrag) + reencryption_signature

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

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

        return Response(response=cfrag_byte_stream, headers=headers)
Beispiel #2
0
    def reencrypt_via_rest(id_as_hex):

        # Get Policy Arrangement
        try:
            arrangement_id = binascii.unhexlify(id_as_hex)
        except (binascii.Error, TypeError):
            return Response(response=b'Invalid arrangement ID', status=405)
        try:
            with ThreadedSession(db_engine) as session:
                arrangement = datastore.get_policy_arrangement(
                    arrangement_id=id_as_hex.encode(), session=session)
        except NotFound:
            return Response(response=arrangement_id, status=404)

        # Get KFrag
        # TODO: Yeah, well, what if this arrangement hasn't been enacted?  1702
        kfrag = KFrag.from_bytes(arrangement.kfrag)

        # Get Work Order
        from nucypher.policy.collections import WorkOrder  # Avoid circular import
        alice_verifying_key_bytes = arrangement.alice_verifying_key.key_data
        alice_verifying_key = UmbralPublicKey.from_bytes(
            alice_verifying_key_bytes)
        alice_address = canonical_address_from_umbral_key(alice_verifying_key)
        work_order_payload = request.data
        work_order = WorkOrder.from_rest_payload(
            arrangement_id=arrangement_id,
            rest_payload=work_order_payload,
            ursula=this_node,
            alice_address=alice_address)
        log.info(
            f"Work Order from {work_order.bob}, signed {work_order.receipt_signature}"
        )

        # Re-encrypt
        response = this_node._reencrypt(
            kfrag=kfrag,
            work_order=work_order,
            alice_verifying_key=alice_verifying_key)

        # Now, Ursula saves this workorder to her database...
        with ThreadedSession(db_engine):
            this_node.datastore.save_workorder(
                bob_verifying_key=bytes(work_order.bob.stamp),
                bob_signature=bytes(work_order.receipt_signature),
                arrangement_id=work_order.arrangement_id)

        headers = {'Content-Type': 'application/octet-stream'}
        return Response(headers=headers, response=response)
Beispiel #3
0
    def reencrypt_via_rest(id_as_hex):

        # Get Policy Arrangement
        try:
            arrangement_id = binascii.unhexlify(id_as_hex)
        except (binascii.Error, TypeError):
            return Response(response=b'Invalid arrangement ID', status=405)
        try:
            # Get KFrag
            # TODO: Yeah, well, what if this arrangement hasn't been enacted?  1702
            with datastore.describe(PolicyArrangement,
                                    id_as_hex) as policy_arrangement:
                kfrag = policy_arrangement.kfrag
                alice_verifying_key = policy_arrangement.alice_verifying_key
        except RecordNotFound:
            return Response(response=arrangement_id, status=404)

        # Get Work Order
        from nucypher.policy.collections import WorkOrder  # Avoid circular import
        alice_address = canonical_address_from_umbral_key(alice_verifying_key)
        work_order_payload = request.data
        work_order = WorkOrder.from_rest_payload(
            arrangement_id=arrangement_id,
            rest_payload=work_order_payload,
            ursula=this_node,
            alice_address=alice_address)
        log.info(
            f"Work Order from {work_order.bob}, signed {work_order.receipt_signature}"
        )

        # Re-encrypt
        response = this_node._reencrypt(
            kfrag=kfrag,
            work_order=work_order,
            alice_verifying_key=alice_verifying_key)

        # Now, Ursula saves this workorder to her database...
        # Note: we give the work order a random ID to store it under.
        with datastore.describe(Workorder, str(uuid.uuid4()),
                                writeable=True) as new_workorder:
            new_workorder.arrangement_id = work_order.arrangement_id
            new_workorder.bob_verifying_key = work_order.bob.stamp.as_umbral_pubkey(
            )
            new_workorder.bob_signature = work_order.receipt_signature

        headers = {'Content-Type': 'application/octet-stream'}
        return Response(headers=headers, response=response)
def test_work_order_with_multiple_capsules(mock_ursula_reencrypts, ursula,
                                           get_random_checksum_address,
                                           federated_bob, federated_alice,
                                           number):

    tasks = [mock_ursula_reencrypts(ursula) for _ in range(number)]
    material = [(task.capsule, task.signature, task.cfrag,
                 task.cfrag_signature) for task in tasks]
    capsules, signatures, cfrags, cfrag_signatures = zip(*material)

    arrangement_id = os.urandom(Arrangement.ID_LENGTH)
    alice_address = canonical_address_from_umbral_key(federated_alice.stamp)
    blockhash = b'\0' * ETH_HASH_BYTE_LENGTH  # TODO: Prove freshness of work order - #259
    identity_evidence = ursula.decentralized_identity_evidence

    # Test construction of WorkOrders by Bob
    work_order = WorkOrder.construct_by_bob(
        arrangement_id=arrangement_id,
        bob=federated_bob,
        alice_verifying=federated_alice.stamp.as_umbral_pubkey(),
        ursula=ursula,
        capsules=capsules)

    receipt_input = WorkOrder.HEADER + bytes(ursula.stamp) + b''.join(
        map(bytes, capsules))
    bob_verifying_pubkey = federated_bob.stamp.as_umbral_pubkey()

    assert work_order.bob == federated_bob
    assert work_order.arrangement_id == arrangement_id
    assert work_order.alice_address == alice_address
    assert len(work_order.tasks) == len(work_order) == number
    for capsule in capsules:
        assert work_order.tasks[capsule].capsule == capsule
        task = WorkOrder.PRETask(capsule, signature=None)
        specification = task.get_specification(ursula.stamp, alice_address,
                                               blockhash, identity_evidence)
        assert work_order.tasks[capsule].signature.verify(
            bob_verifying_pubkey, specification)
    assert work_order.receipt_signature.verify(bob_verifying_pubkey,
                                               receipt_input)
    assert work_order.ursula == ursula
    assert work_order.blockhash == blockhash
    assert not work_order.completed

    # Test WorkOrders' payload serialization and deserialization
    tasks_bytes = b''.join(map(bytes, work_order.tasks.values()))
    expected_payload = bytes(work_order.receipt_signature) + bytes(
        federated_bob.stamp) + blockhash + tasks_bytes

    payload = work_order.payload()
    assert expected_payload == payload

    same_work_order = WorkOrder.from_rest_payload(
        arrangement_id=arrangement_id,
        rest_payload=payload,
        ursula=ursula,
        alice_address=alice_address)

    assert same_work_order.bob == federated_bob
    assert same_work_order.arrangement_id == arrangement_id
    assert same_work_order.alice_address == alice_address
    assert len(same_work_order.tasks) == len(same_work_order) == number
    for capsule in capsules:
        assert same_work_order.tasks[capsule].capsule == capsule
        assert same_work_order.tasks[capsule].signature == work_order.tasks[
            capsule].signature
    assert same_work_order.receipt_signature == work_order.receipt_signature
    assert same_work_order.ursula == ursula
    assert same_work_order.blockhash == blockhash
    assert not same_work_order.completed

    tampered_payload = bytearray(payload)
    somewhere_over_the_blockhash = 64 + 33 + 5
    tampered_payload[somewhere_over_the_blockhash] = 255 - payload[
        somewhere_over_the_blockhash]
    with pytest.raises(InvalidSignature):
        _ = WorkOrder.from_rest_payload(arrangement_id=arrangement_id,
                                        rest_payload=bytes(tampered_payload),
                                        ursula=ursula,
                                        alice_address=alice_address)

    # Testing WorkOrder.complete()

    # Let's use the original task signatures in our WorkOrder, instead
    for capsule, task_signature in zip(capsules, signatures):
        work_order.tasks[capsule].signature = task_signature

    # Now, complete() works as intended
    good_cfrags = work_order.complete(list(zip(cfrags, cfrag_signatures)))
    assert work_order.completed
    assert len(good_cfrags) == number

    # Testing some additional expected exceptions
    with pytest.raises(ValueError,
                       match="Ursula gave back the wrong number of cfrags"):
        work_order.complete(list(zip(cfrags, cfrag_signatures))[1:])

    bad_cfrag_signature = ursula.stamp(os.urandom(10))
    with pytest.raises(InvalidSignature,
                       match=f"{cfrags[0]} is not properly signed by Ursula."):
        work_order.complete(
            list(
                zip(cfrags,
                    [bad_cfrag_signature] + list(cfrag_signatures[1:]))))