Excavate reencryption logic onto Ursula proper.

pull/1523/head
Kieran R. Prasch 2019-12-09 23:07:49 -08:00
parent eba53f3206
commit 77b297ede3
4 changed files with 56 additions and 27 deletions

View File

@ -1252,21 +1252,42 @@ class Ursula(Teacher, Character, Worker):
return constants.BYTESTRING_IS_URSULA_IFACE_INFO + bytes(self)
#
# Utilities
# Work Orders & Re-Encryption
#
def work_orders(self, bob=None):
"""
TODO: This is better written as a model method for Ursula's datastore.
"""
if not bob:
return self._work_orders
else:
work_orders_from_bob = []
for work_order in self._work_orders:
if work_order.bob == bob:
work_orders_from_bob.append(work_order)
return work_orders_from_bob
def work_orders(self, bob=None) -> List['WorkOrder']:
with ThreadedSession(self.datastore.engine):
if not bob: # All
return self.datastore.get_workorders()
else: # Filter
work_orders_from_bob = self.datastore.get_workorders(bob_verifying_key=bytes(bob.stamp))
return work_orders_from_bob
def _reencrypt(self, kfrag: KFrag, work_order: 'WorkOrder', alice_verifying_key: UmbralPublicKey):
# Prepare a bytestring for concatenating re-encrypted
# capsule data for each work order task.
cfrag_byte_stream = bytes()
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(self.stamp(bytes(task.signature)))
# Ursula sets Alice's verifying key for capsule correctness verification.
capsule = task.capsule
capsule.set_correctness_keys(verifying=alice_verifying_key)
# Then re-encrypts the fragment.
cfrag = pre.reencrypt(kfrag, capsule, metadata=reencryption_metadata) # <--- pyUmbral
self.log.info(f"Re-encrypted capsule {capsule} -> made {cfrag}.")
# Next, Ursula signs to commit to her results.
reencryption_signature = self.stamp(bytes(cfrag))
cfrag_byte_stream += VariableLengthBytestring(cfrag) + reencryption_signature
# ... and finally returns all the re-encrypted bytes
return cfrag_byte_stream
class Enrico(Character):

View File

@ -124,7 +124,7 @@ def paint_node_status(emitter, ursula, start_time):
'Rest Interface ...... {}'.format(ursula.rest_url()),
'Node Storage Type ... {}'.format(ursula.node_storage._name.capitalize()),
'Known Nodes ......... {}'.format(len(ursula.known_nodes)),
'Work Orders ......... {}'.format(len(ursula._work_orders)),
'Work Orders ......... {}'.format(len(ursula.work_orders())),
teacher]
if not ursula.federated_only:

View File

@ -291,29 +291,37 @@ def make_rest_app(
@rest_app.route('/kFrag/<id_as_hex>/reencrypt', methods=["POST"])
def reencrypt_via_rest(id_as_hex):
from nucypher.policy.collections import WorkOrder # Avoid circular import
arrangement_id = binascii.unhexlify(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)
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)
# Get KFrag
kfrag = KFrag.from_bytes(arrangement.kfrag) # Careful! :-)
# 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=request.data,
rest_payload=work_order_payload,
ursula=this_node,
alice_address=alices_address)
alice_address=alice_address)
log.info(f"Work Order from {work_order.bob}, signed {work_order.receipt_signature}")
cfrag_byte_stream = b""
# 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):

View File

@ -74,4 +74,4 @@ def test_workorder_sqlite_keystore(test_keystore):
# Test del workorder
deleted = test_keystore.del_workorders(arrangement_id)
assert deleted > 0
assert test_keystore.get_workorders(arrangement_id) == 0
assert len(test_keystore.get_workorders(arrangement_id)) == 0