Bundle policy encrypting key with TreasureMap

pull/2802/head
Bogdan Opanchuk 2021-09-29 22:17:21 -07:00
parent 2a85ccf768
commit ef0e619684
30 changed files with 25 additions and 69 deletions

View File

@ -362,7 +362,6 @@ Then Bob can retrieve and decrypt the message kit:
cleartexts = bob.retrieve_and_decrypt(
message_kits=[message_kit],
policy_encrypting_key=policy.public_key,
alice_verifying_key=alice_public_key,
encrypted_treasure_map=policy.treasure_map,
)

View File

@ -147,7 +147,6 @@ This endpoint controls the ``Bob.retrieve_and_decrypt`` method.
- URL: ``/retrieve_and_decrypt``
- HTTP Method: ``POST``
- Required arguments:
- ``policy_encrypting_key`` -- encoded as hex
- ``alice_verifying_key`` -- encoded as hex
- ``encrypted_treasure_map`` -- encoded as base64
- ``message_kits`` -- list of message kits each encoded as base64

View File

@ -648,9 +648,6 @@ Parameters
| ``bob_encrypting_key`` | String | Bob's encrypting key encoded as hex. |
+-------------------------------------------+---------------+----------------------------------------+
| ``bob_verifying_key`` | String | Bob's verifying key encoded as hex. |
+-------------------------------------------+---------------+----------------------------------------+
| ``policy_encrypting_key`` | String | | Encrypting key used for the policy |
| | | | encoded as hex. |
+-------------------------------------------+---------------+----------------------------------------+
* A single *retrieval kit* is an encapsulation of the information necessary to obtain cfrags from Ursulas.

View File

@ -150,7 +150,6 @@ for counter, plaintext in enumerate(finnegans_wake):
# Now Bob can retrieve the original message.
delivered_cleartexts = bob.retrieve_and_decrypt([single_passage_message_kit],
policy_encrypting_key=policy_public_key,
alice_verifying_key=alice_verifying_key,
encrypted_treasure_map=policy.treasure_map)

View File

@ -154,7 +154,6 @@ for counter, plaintext in enumerate(finnegans_wake):
# Now Bob can retrieve the original message by requesting re-encryption from nodes.
cleartexts = bob.retrieve_and_decrypt([message_kit],
policy_encrypting_key=policy_public_key,
alice_verifying_key=alice_verifying_key,
encrypted_treasure_map=policy.treasure_map)

View File

@ -102,7 +102,6 @@ for message_kit in message_kits:
start = timer()
retrieved_plaintexts = doctor.retrieve_and_decrypt(
[message_kit],
policy_encrypting_key=policy_pubkey,
alice_verifying_key=alices_sig_pubkey,
encrypted_treasure_map=treasure_map
)

View File

@ -147,7 +147,6 @@ class BobInterface(CharacterPublicInterface):
@attach_schema(bob.RetrieveAndDecrypt)
def retrieve_and_decrypt(self,
policy_encrypting_key: PublicKey,
alice_verifying_key: PublicKey,
message_kits: List[MessageKit],
encrypted_treasure_map: EncryptedTreasureMap) -> dict:
@ -155,7 +154,6 @@ class BobInterface(CharacterPublicInterface):
Character control endpoint for re-encrypting and decrypting policy data.
"""
plaintexts = self.implementer.retrieve_and_decrypt(message_kits,
policy_encrypting_key=policy_encrypting_key,
alice_verifying_key=alice_verifying_key,
encrypted_treasure_map=encrypted_treasure_map)

View File

@ -24,11 +24,6 @@ from nucypher.control.specifications.base import BaseSchema
class RetrieveAndDecrypt(BaseSchema):
policy_encrypting_key = character_fields.Key(
required=True,
load_only=True,
click=options.option_policy_encrypting_key(required=True)
)
alice_verifying_key = character_fields.Key(
required=True,
load_only=True,

View File

@ -543,7 +543,6 @@ class Bob(Character):
message_kits: Sequence[Union[MessageKit, PolicyMessageKit]],
alice_verifying_key: PublicKey, # KeyFrag signer's key
encrypted_treasure_map: EncryptedTreasureMap,
policy_encrypting_key: PublicKey, # TODO: #2792
) -> List[PolicyMessageKit]:
"""
Attempts to retrieve reencrypted capsule fragments
@ -569,7 +568,7 @@ class Bob(Character):
# Normalize input
message_kits: List[PolicyMessageKit] = [
PolicyMessageKit.from_message_kit(message_kit, policy_encrypting_key, treasure_map.threshold)
PolicyMessageKit.from_message_kit(message_kit, treasure_map.policy_encrypting_key, treasure_map.threshold)
if isinstance(message_kit, MessageKit) else message_kit
for message_kit in message_kits
]
@ -584,8 +583,7 @@ class Bob(Character):
retrieval_kits=retrieval_kits,
alice_verifying_key=alice_verifying_key,
bob_encrypting_key=self.public_keys(DecryptingPower),
bob_verifying_key=self.stamp.as_umbral_pubkey(),
policy_encrypting_key=policy_encrypting_key)
bob_verifying_key=self.stamp.as_umbral_pubkey())
# Refill message kits with newly retrieved capsule frags
results = []

View File

@ -352,7 +352,6 @@ def make_card(general_config, character_options, config_file, nickname):
def retrieve_and_decrypt(general_config,
character_options,
config_file,
policy_encrypting_key,
alice_verifying_key,
treasure_map,
message_kit,
@ -407,7 +406,6 @@ def retrieve_and_decrypt(general_config,
# Request
bob_request_data = {
'policy_encrypting_key': policy_encrypting_key,
'alice_verifying_key': alice_verifying_key,
'message_kits': message_kits,
'encrypted_treasure_map': treasure_map

View File

@ -344,10 +344,12 @@ class TreasureMap(Versioned):
def __init__(self,
threshold: int,
hrac: HRAC,
policy_encrypting_key: PublicKey,
destinations: Dict[ChecksumAddress, MessageKit]):
self.threshold = threshold
self.destinations = destinations
self.hrac = hrac
self.policy_encrypting_key = policy_encrypting_key
# A little awkward, but saves us a key length in serialization
self.publisher_verifying_key = list(destinations.values())[0].sender_verifying_key
@ -369,6 +371,7 @@ class TreasureMap(Versioned):
@classmethod
def construct_by_publisher(cls,
hrac: HRAC,
policy_encrypting_key: PublicKey,
signer: Signer,
# TODO: a better way to do it? A structure/namedtuple perhaps?
assigned_kfrags: Sequence[Tuple[ChecksumAddress, PublicKey, VerifiedKeyFrag]],
@ -397,7 +400,10 @@ class TreasureMap(Versioned):
destinations[ursula_address] = encrypted_kfrag
return cls(threshold=threshold, hrac=hrac, destinations=destinations)
return cls(threshold=threshold,
hrac=hrac,
policy_encrypting_key=policy_encrypting_key,
destinations=destinations)
@classmethod
def _brand(cls) -> bytes:
@ -413,7 +419,7 @@ class TreasureMap(Versioned):
def _payload(self) -> bytes:
"""Returns the unversioned bytes serialized representation of this instance."""
return self.threshold.to_bytes(1, "big") + bytes(self.hrac) + self._nodes_as_bytes()
return self.threshold.to_bytes(1, "big") + bytes(self.hrac) + bytes(self.policy_encrypting_key) + self._nodes_as_bytes()
@classmethod
def _from_bytes_current(cls, data):
@ -421,6 +427,7 @@ class TreasureMap(Versioned):
main_splitter = BytestringSplitter(
(int, 1, {'byteorder': 'big'}),
hrac_splitter,
key_splitter,
)
ursula_and_kfrag_payload_splitter = BytestringSplitter(
@ -429,12 +436,12 @@ class TreasureMap(Versioned):
)
try:
threshold, hrac, remainder = main_splitter(data, return_remainder=True)
threshold, hrac, policy_encrypting_key, remainder = main_splitter(data, return_remainder=True)
ursula_and_kfrags = ursula_and_kfrag_payload_splitter.repeat(remainder)
except BytestringSplittingError as e:
raise ValueError('Invalid treasure map contents.') from e
destinations = {u: k for u, k in ursula_and_kfrags}
return cls(threshold, hrac, destinations)
return cls(threshold, hrac, policy_encrypting_key, destinations)
def encrypt(self,
signer: Signer,

View File

@ -259,7 +259,6 @@ class RetrievalClient:
alice_verifying_key: PublicKey, # KeyFrag signer's key
bob_encrypting_key: PublicKey, # User's public key (reencryption target)
bob_verifying_key: PublicKey,
policy_encrypting_key: PublicKey, # Key used to create the policy
) -> List[RetrievalResult]:
self._ensure_ursula_availability(treasure_map)
@ -286,7 +285,7 @@ class RetrievalClient:
try:
cfrags = self._request_reencryption(ursula=ursula,
reencryption_request=reencryption_request,
delegating_key=policy_encrypting_key,
delegating_key=treasure_map.policy_encrypting_key,
receiving_key=bob_encrypting_key)
except Exception as e:
# TODO (#2789): at this point we can separate the exceptions to "acceptable"

View File

@ -249,6 +249,7 @@ class Policy(ABC):
for ursula, vkfrag in zip(arrangements, self.kfrags)]
treasure_map = TreasureMap.construct_by_publisher(hrac=self.hrac,
policy_encrypting_key=self.public_key,
signer=self.publisher.stamp.as_umbral_signer(),
assigned_kfrags=assigned_kfrags,
threshold=self.threshold)

View File

@ -61,14 +61,12 @@ class PorterInterface(ControlInterface):
alice_verifying_key: PublicKey,
bob_encrypting_key: PublicKey,
bob_verifying_key: PublicKey,
policy_encrypting_key: PublicKey,
) -> dict:
retrieval_results = self.implementer.retrieve_cfrags(treasure_map=treasure_map,
retrieval_kits=retrieval_kits,
alice_verifying_key=alice_verifying_key,
bob_encrypting_key=bob_encrypting_key,
bob_verifying_key=bob_verifying_key,
policy_encrypting_key=policy_encrypting_key)
bob_verifying_key=bob_verifying_key)
results = retrieval_results # list of RetrievalResult objects
response_data = {'retrieval_results': results}
return response_data

View File

@ -166,14 +166,6 @@ class BobRetrieveCFrags(BaseSchema):
help="Bob's verifying key as a hexadecimal string",
type=click.STRING,
required=True))
policy_encrypting_key = character_fields.Key(
required=True,
load_only=True,
click=click.option(
'--policy-encrypting-key',
help="Encrypting Public Key for Policy as hexadecimal string",
type=click.STRING,
required=True))
# output
retrieval_results = marshmallow_fields.List(marshmallow_fields.Nested(fields.RetrievalResultSchema), dump_only=True)

View File

@ -159,10 +159,10 @@ the Pipe for nucypher network operations
alice_verifying_key: PublicKey,
bob_encrypting_key: PublicKey,
bob_verifying_key: PublicKey,
policy_encrypting_key: PublicKey) -> List[RetrievalResult]:
) -> List[RetrievalResult]:
client = RetrievalClient(self)
return client.retrieve_cfrags(treasure_map, retrieval_kits,
alice_verifying_key, bob_encrypting_key, bob_verifying_key, policy_encrypting_key)
alice_verifying_key, bob_encrypting_key, bob_verifying_key)
def _make_staker_reservoir(self,
quantity: int,

View File

@ -124,7 +124,6 @@ def retrieve_control_request(blockchain_alice, blockchain_bob, enacted_blockchai
message_kit = capsule_side_channel_blockchain()
params = {
'policy_encrypting_key': bytes(enacted_blockchain_policy.public_key).hex(),
'alice_verifying_key': bytes(enacted_blockchain_policy.publisher_verifying_key).hex(),
'message_kits': [b64encode(bytes(message_kit)).decode()],
'encrypted_treasure_map': b64encode(bytes(enacted_blockchain_policy.treasure_map)).decode()

View File

@ -303,7 +303,6 @@ def test_web_character_control_lifecycle(alice_web_controller_test_client,
# This is sidechannel policy metadata. It should be given to Bob by the
# application developer at some point.
policy_pubkey_enc_hex = alice_response_data['result']['policy_encrypting_key']
alice_verifying_key_hex = alice_response_data['result']['alice_verifying_key']
# Encrypt some data via Enrico control
@ -328,7 +327,6 @@ def test_web_character_control_lifecycle(alice_web_controller_test_client,
encoded_message_kit = b64encode(bytes(bob_message_kit)).decode()
bob_request_data = {
'policy_encrypting_key': policy_pubkey_enc_hex,
'alice_verifying_key': alice_verifying_key_hex,
'message_kits': [encoded_message_kit],
'encrypted_treasure_map': alice_response_data['result']['treasure_map']

View File

@ -55,7 +55,6 @@ def test_policy_simple_sinpa(blockchain_ursulas,
with pytest.raises(Ursula.NotEnoughUrsulas): # Return a more descriptive request error?
blockchain_bob.retrieve_and_decrypt([message_kit],
policy_encrypting_key=bupkiss_policy.public_key,
alice_verifying_key=amonia.stamp,
encrypted_treasure_map=bupkiss_policy.treasure_map)
@ -92,7 +91,6 @@ def test_try_to_post_free_arrangement_by_hacking_enact(blockchain_ursulas,
with pytest.raises(Ursula.NotEnoughUrsulas): # Return a more descriptive request error?
blockchain_bob.retrieve_and_decrypt([message_kit],
policy_encrypting_key=bupkiss_policy.public_key,
alice_verifying_key=amonia.stamp,
encrypted_treasure_map=bupkiss_policy.treasure_map)
@ -127,6 +125,5 @@ def test_pay_a_flunky_instead_of_the_arranged_ursula(blockchain_alice,
with pytest.raises(Ursula.NotEnoughUrsulas):
blockchain_bob.retrieve_and_decrypt([message_kit],
policy_encrypting_key=bupkiss_policy.public_key,
alice_verifying_key=amonia.stamp,
encrypted_treasure_map=bupkiss_policy.treasure_map)

View File

@ -158,8 +158,7 @@ def test_blockchain_ursulas_reencrypt(blockchain_ursulas, blockchain_alice, bloc
plaintexts = blockchain_bob.retrieve_and_decrypt([message_kit],
encrypted_treasure_map=_policy.treasure_map,
alice_verifying_key=blockchain_alice.stamp.as_umbral_pubkey(),
policy_encrypting_key=_policy.public_key)
alice_verifying_key=blockchain_alice.stamp.as_umbral_pubkey())
assert plaintexts == [message]
# Let's consider also that a node may be down when granting

View File

@ -363,7 +363,6 @@ def run_entire_cli_lifecycle(click_runner,
'--config-file', str(bob_configuration_file_location.absolute()),
'--message-kit', ciphertext_message_kit,
'--treasure-map', side_channel.fetch_treasure_map(),
'--policy-encrypting-key', policy_encrypting_key,
'--alice-verifying-key', alice_signing_key)
retrieve_response = click_runner.invoke(nucypher_cli, retrieve_args, catch_exceptions=False, env=envvars)

View File

@ -158,7 +158,6 @@ def test_bob_retrieve_and_decrypt(click_runner,
'--teacher', teacher_uri,
'--config-file', bob_config_file,
'--message-kit', message_kits_b64[0],
'--policy-encrypting-key', policy_encrypting_key_hex,
'--treasure-map', encrypted_treasure_map_b64,
)
retrieve_response = click_runner.invoke(nucypher_cli,
@ -175,7 +174,6 @@ def test_bob_retrieve_and_decrypt(click_runner,
'--teacher', teacher_uri,
'--config-file', bob_config_file,
'--message-kit', message_kits_b64[0],
'--policy-encrypting-key', policy_encrypting_key_hex,
'--alice-verifying-key', alice_verifying_key_hex,
'--alice', 'rando-card-nickname',
'--treasure-map', encrypted_treasure_map_b64,
@ -206,7 +204,6 @@ def test_bob_retrieve_and_decrypt(click_runner,
'--teacher', teacher_uri,
'--config-file', bob_config_file,
'--message-kit', message_kits_b64[0],
'--policy-encrypting-key', policy_encrypting_key_hex,
'--alice-verifying-key', alice_verifying_key_hex,
'--treasure-map', encrypted_treasure_map_b64,
)
@ -237,7 +234,6 @@ def test_bob_retrieve_and_decrypt(click_runner,
'--message-kit', message_kits_b64[1],
'--message-kit', message_kits_b64[2],
'--message-kit', message_kits_b64[3],
'--policy-encrypting-key', policy_encrypting_key_hex,
'--alice-verifying-key', alice_verifying_key_hex,
'--treasure-map', encrypted_treasure_map_b64
)

View File

@ -643,7 +643,6 @@ def test_collect_rewards_integration(click_runner,
# Decrypt
cleartexts = blockchain_bob.retrieve_and_decrypt([message_kit],
policy_encrypting_key=blockchain_policy.public_key,
alice_verifying_key=verifying_key,
encrypted_treasure_map=blockchain_policy.treasure_map)
assert random_data == cleartexts[0]

View File

@ -121,7 +121,6 @@ def retrieve_control_request(federated_bob, enacted_federated_policy, capsule_si
message_kit = capsule_side_channel()
params = {
'policy_encrypting_key': bytes(enacted_federated_policy.public_key).hex(),
'alice_verifying_key': bytes(enacted_federated_policy.publisher_verifying_key).hex(),
'message_kits': [b64encode(bytes(message_kit)).decode()],
'encrypted_treasure_map': b64encode(bytes(enacted_federated_policy.treasure_map)).decode()

View File

@ -304,7 +304,6 @@ def test_web_character_control_lifecycle(alice_web_controller_test_client,
# This is sidechannel policy metadata. It should be given to Bob by the
# application developer at some point.
policy_pubkey_enc_hex = alice_response_data['result']['policy_encrypting_key']
alice_verifying_key_hex = alice_response_data['result']['alice_verifying_key']
# Encrypt some data via Enrico control
@ -329,7 +328,6 @@ def test_web_character_control_lifecycle(alice_web_controller_test_client,
encoded_message_kit = b64encode(bytes(bob_message_kit)).decode()
bob_request_data = {
'policy_encrypting_key': policy_pubkey_enc_hex,
'alice_verifying_key': alice_verifying_key_hex,
'message_kits': [encoded_message_kit],
'encrypted_treasure_map': alice_response_data['result']['treasure_map']

View File

@ -31,7 +31,6 @@ from tests.utils.middleware import MockRestMiddleware, NodeIsDownMiddleware
def _policy_info_kwargs(enacted_policy):
return dict(
encrypted_treasure_map=enacted_policy.treasure_map,
policy_encrypting_key=enacted_policy.public_key,
alice_verifying_key=enacted_policy.publisher_verifying_key,
)

View File

@ -47,7 +47,6 @@ def test_federated_bob_full_retrieve_flow(federated_ursulas,
alices_verifying_key = federated_alice.stamp.as_umbral_pubkey()
delivered_cleartexts = federated_bob.retrieve_and_decrypt([the_message_kit],
policy_encrypting_key=enacted_federated_policy.public_key,
alice_verifying_key=alices_verifying_key,
encrypted_treasure_map=enacted_federated_policy.treasure_map)
@ -99,14 +98,12 @@ def test_bob_retrieves(federated_alice,
# Bob takes the message_kit and retrieves the message within
delivered_cleartexts = bob.retrieve_and_decrypt([message_kit],
policy_encrypting_key=policy.public_key,
alice_verifying_key=alices_verifying_key,
encrypted_treasure_map=policy.treasure_map)
assert plaintext == delivered_cleartexts[0]
cleartexts_delivered_a_second_time = bob.retrieve_and_decrypt([message_kit],
policy_encrypting_key=policy.public_key,
alice_verifying_key=alices_verifying_key,
encrypted_treasure_map=policy.treasure_map)
@ -120,7 +117,6 @@ def test_bob_retrieves(federated_alice,
# One thing to note here is that Bob *can* still retrieve with the cached CFrags,
# even though this Policy has been revoked. #892
_cleartexts = bob.retrieve_and_decrypt([message_kit],
policy_encrypting_key=policy.public_key,
alice_verifying_key=alices_verifying_key,
encrypted_treasure_map=policy.treasure_map)
assert _cleartexts == delivered_cleartexts # TODO: 892
@ -143,7 +139,6 @@ def test_bob_retrieves_with_treasure_map(
# Deserialized treasure map
text1 = federated_bob.retrieve_and_decrypt(
[message_kit],
policy_encrypting_key=enacted_federated_policy.public_key,
alice_verifying_key=alice_verifying_key,
encrypted_treasure_map=treasure_map)
@ -171,6 +166,5 @@ def test_bob_retrieves_too_late(federated_bob, federated_ursulas,
# with pytest.raises(Ursula.NotEnoughUrsulas):
federated_bob.retrieve_and_decrypt(
[message_kit],
policy_encrypting_key=enacted_federated_policy.public_key,
alice_verifying_key=alice_verifying_key,
encrypted_treasure_map=treasure_map)

View File

@ -29,7 +29,7 @@ def random_federated_treasure_map_data(federated_alice, federated_bob, federated
label = b'policy label'
threshold = 2
shares = threshold + 1
_policy_key, kfrags = federated_alice.generate_kfrags(bob=federated_bob, label=label, threshold=threshold, shares=shares)
policy_key, kfrags = federated_alice.generate_kfrags(bob=federated_bob, label=label, threshold=threshold, shares=shares)
hrac = HRAC.derive(publisher_verifying_key=federated_alice.stamp.as_umbral_pubkey(),
bob_verifying_key=federated_bob.stamp.as_umbral_pubkey(),
label=label)
@ -39,6 +39,7 @@ def random_federated_treasure_map_data(federated_alice, federated_bob, federated
for ursula, vkfrag in zip(list(federated_ursulas)[:shares], kfrags)]
random_treasure_map = TreasureMap.construct_by_publisher(hrac=hrac,
policy_encrypting_key=policy_key,
signer=federated_alice.stamp.as_umbral_signer(),
assigned_kfrags=assigned_kfrags,
threshold=threshold)

View File

@ -41,6 +41,7 @@ def test_complete_treasure_map_journey(federated_alice, federated_bob, federated
for ursula, vkfrag in zip(ursulas, kfrags)]
treasure_map = TreasureMap.construct_by_publisher(hrac=hrac,
policy_encrypting_key=idle_federated_policy.public_key,
signer=federated_alice.stamp.as_umbral_signer(),
assigned_kfrags=assigned_kfrags,
threshold=1)
@ -94,6 +95,7 @@ def test_treasure_map_versioning(mocker, federated_alice, federated_bob, federat
for ursula, vkfrag in zip(list(federated_ursulas)[:len(kfrags)], kfrags)]
treasure_map = TreasureMap.construct_by_publisher(hrac=hrac,
policy_encrypting_key=idle_federated_policy.public_key,
signer=federated_alice.stamp.as_umbral_signer(),
assigned_kfrags=assigned_kfrags,
threshold=2)

View File

@ -59,8 +59,7 @@ def retrieval_request_setup(enacted_policy, bob, alice, original_message: bytes
retrieval_kits=[encode_bytes(RetrievalKitField, RetrievalKit.from_message_kit(message_kit))],
alice_verifying_key=encode_bytes(Key, alice.stamp.as_umbral_pubkey()),
bob_encrypting_key=encode_bytes(Key, bob.public_keys(DecryptingPower)),
bob_verifying_key=encode_bytes(Key, bob.stamp.as_umbral_pubkey()),
policy_encrypting_key=encode_bytes(Key, enacted_policy.public_key)),
bob_verifying_key=encode_bytes(Key, bob.stamp.as_umbral_pubkey())),
message_kit)
@ -70,5 +69,4 @@ def retrieval_params_decode_from_rest(retrieval_params: Dict) -> Dict:
retrieval_kits=[decode_bytes(RetrievalKitField, kit) for kit in retrieval_params['retrieval_kits']],
alice_verifying_key=decode_bytes(Key, retrieval_params['alice_verifying_key']),
bob_encrypting_key=decode_bytes(Key, retrieval_params['bob_encrypting_key']),
bob_verifying_key=decode_bytes(Key, retrieval_params['bob_verifying_key']),
policy_encrypting_key=decode_bytes(Key, retrieval_params['policy_encrypting_key']))
bob_verifying_key=decode_bytes(Key, retrieval_params['bob_verifying_key']))