def add_contents(self, alicia, my_label, contents): """ cid = client.add_contents( policy_pubkey=policy_pub_key ) """ policy_pubkey = alicia.get_policy_pubkey_from_label(my_label) data_source = Enrico(policy_encrypting_key=policy_pubkey) data_source_public_key = bytes(data_source.stamp) heart_rate = 80 now = time.time() kits = list() heart_rate = contents now += 3 heart_rate_data = { 'heart_rate': heart_rate, 'timestamp': now, } plaintext = msgpack.dumps(heart_rate_data, use_bin_type=True) message_kit, _signature = data_source.encrypt_message(plaintext) kit_bytes = message_kit.to_bytes() kits.append(kit_bytes) data = { 'data_source': data_source_public_key, 'kits': kits, } # print("🚀 ADDING TO IPFS D-STORAGE NETWORK 🚀") d = msgpack.dumps(data, use_bin_type=True) ### NETWORK ERROR OUT ON FALLBACK cid = self.ipfs_gateway_api.add_bytes(d) # print("File Address:\t%s" % cid) return cid
def enrico(click_config, action, policy_encrypting_key, dry_run, http_port, message): """ "Enrico the Encryptor" management commands. """ # # Validate # if not policy_encrypting_key: raise click.BadArgumentUsage( '--policy-encrypting-key is required to start Enrico.') # Banner emitter = click_config.emitter emitter.clear() emitter.banner(ENRICO_BANNER.format(policy_encrypting_key)) # # Make Enrico # policy_encrypting_key = UmbralPublicKey.from_bytes( bytes.fromhex(policy_encrypting_key)) ENRICO = Enrico(policy_encrypting_key=policy_encrypting_key) ENRICO.controller.emitter = emitter # TODO: set it on object creation? Or not set at all? # # Actions # if action == 'run': # RPC if click_config.json_ipc: rpc_controller = ENRICO.make_rpc_controller() _transport = rpc_controller.make_control_transport() rpc_controller.start() return ENRICO.log.info('Starting HTTP Character Web Controller') controller = ENRICO.make_web_controller() return controller.start(http_port=http_port, dry_run=dry_run) elif action == 'encrypt': # Validate if not message: raise click.BadArgumentUsage( '--message is a required flag to encrypt.') # Request encryption_request = {'message': message} response = ENRICO.controller.encrypt_message( request=encryption_request) return response else: raise click.BadArgumentUsage
def uploadData(self, label, file): policy_pubkey = self.Alice.get_policy_encrypting_key_from_label(label.encode("utf-8")) data_source = Enrico(policy_encrypting_key=policy_pubkey) data_source_public_key = bytes(data_source.stamp) now = time.time() kits = list() now += 5 data_representation = { 'data': file, 'timestamp': now, } plaintext = msgpack.dumps(data_representation, use_bin_type=True) message_kit, _signature = data_source.encrypt_message(plaintext) kit_bytes = message_kit.to_bytes() kits.append(kit_bytes) data = { 'data_source': data_source_public_key, 'kits': kits, } d = msgpack.dumps(data, use_bin_type=True) ipfs_hash = self.ipfs_gateway_api.add_bytes(d) receipt = { "data_source_public_key" : data_source_public_key.hex(), "hash_key" : ipfs_hash } return receipt
def __call__(self): enrico = Enrico( policy_encrypting_key=enacted_blockchain_policy.public_key) message = "Welcome to flippering number {}.".format( len(self.messages)).encode() message_kit, _signature = enrico.encrypt_message(message) self.messages.append((message_kit, enrico)) return message_kit, enrico
def enrico(click_config, action, policy_encrypting_key, dry_run, http_port, message): """ Start and manage an "Enrico" character control HTTP server """ # # Validate # if not policy_encrypting_key: raise click.BadArgumentUsage('--policy-encrypting-key is required to start Enrico.') # Banner click.clear() if not click_config.json_ipc and not click_config.quiet: click.secho(ENRICO_BANNER) # # Make Enrico # policy_encrypting_key = UmbralPublicKey.from_bytes(bytes.fromhex(policy_encrypting_key)) ENRICO = Enrico(policy_encrypting_key=policy_encrypting_key) if click_config.json_ipc: ENRICO.controller.emitter = JSONRPCStdoutEmitter(quiet=click_config.quiet) # # Actions # if action == 'run': # RPC if click_config.json_ipc: rpc_controller = ENRICO.make_rpc_controller() _transport = rpc_controller.make_control_transport() rpc_controller.start() return ENRICO.log.info('Starting HTTP Character Web Controller') controller = ENRICO.make_web_controller() return controller.start(http_port=http_port, dry_run=dry_run) elif action == 'encrypt': # Validate if not message: raise click.BadArgumentUsage('--message is a required flag to encrypt.') # Request encryption_request = {'message': message} response = ENRICO.controller.encrypt_message(request=encryption_request) return response else: raise click.BadArgumentUsage
def post(self): policy_key = request.json['policy_pubkey'] data = request.json['data'] enrico = Enrico(policy_encrypting_key=UmbralPublicKey.from_bytes( bytes.fromhex(policy_key))) message_kit, _signature = enrico.encrypt_message(data.encode()) result = {} result["ciphertext"] = message_kit.to_bytes().hex() result["enrico"] = bytes(enrico.stamp).hex() return json.dumps(result)
def _make_message_kits(policy_pubkey): messages = [b"plaintext1", b"plaintext2", b"plaintext3"] message_kits = [] for message in messages: # Using different Enricos, because why not. enrico = Enrico(policy_encrypting_key=policy_pubkey) message_kit = enrico.encrypt_message(message) message_kits.append(message_kit) return messages, message_kits
def test_alice_can_decrypt(federated_alice): label = b"boring test label" policy_pubkey = federated_alice.get_policy_encrypting_key_from_label(label) enrico = Enrico(policy_encrypting_key=policy_pubkey) message = b"boring test message" message_kit = enrico.encrypt_message(plaintext=message) # Interesting thing: if Alice wants to decrypt, she needs to provide the label directly. cleartexts = federated_alice.decrypt_message_kit(label=label, message_kit=message_kit) assert cleartexts == [message]
def reencrypt_segment(enc_data, policy_metadata, listener): policy_pubkey = UmbralPublicKey.from_bytes( bytes.fromhex(policy_metadata["policy_pubkey"])) alices_sig_pubkey = UmbralPublicKey.from_bytes( bytes.fromhex(policy_metadata["alice_sig_pubkey"])) label = policy_metadata["label"].encode() data = msgpack.loads(enc_data) message_kit = UmbralMessageKit.from_bytes((data[b'track_segment_data'])) data_source = Enrico.from_public_keys(verifying_key=data[b'data_source'], policy_encrypting_key=policy_pubkey) plaintext = None try: start = timer() retrieved_plaintexts = listener.retrieve( message_kit, label=label, enrico=data_source, alice_verifying_key=alices_sig_pubkey) end = timer() plaintext = retrieved_plaintexts[0] except Exception as e: # We just want to know what went wrong and continue the demo traceback.print_exc() return plaintext
def decrypt(self, channel_reader: object) -> bytes: ''' Decrypt extsting message using ChannelReader instance :param BOB: :return: ''' policy_pubkey_restored = UmbralPublicKey.from_bytes( self.policy_pubkey_bytes) data_source_restored = Enrico.from_public_keys( {SigningPower: self.data_source_pubkey_bytes}, policy_encrypting_key=policy_pubkey_restored) channel_reader.BOB.join_policy(self.label_bytes, self.alice_pubkey_bytes) alices_sig_pubkey = UmbralPublicKey.from_bytes( bytes(self.alice_pubkey_bytes)) message_kit_object = UmbralMessageKit.from_bytes(self.kit_bytes) return channel_reader.BOB.retrieve( message_kit=message_kit_object, data_source=data_source_restored, alice_verifying_key=alices_sig_pubkey, label=self.label_bytes)
def decrypt_data(self, data_source_public_key, data, policy_info): """ Decrypt data Args: data_source_public_key (bytes): data_source_public_key data (bytes): encrypted data policy_info (dict): dict containing policy_pubkey, alice_sig_pubkey and label keys Returns: retrieved_plaintexts (list): list of str """ policy_pubkey = UmbralPublicKey.from_bytes( bytes.fromhex(policy_info["policy_pubkey"])) alice_sig_pubkey = UmbralPublicKey.from_bytes( bytes.fromhex(policy_info["alice_sig_pubkey"])) label = policy_info["label"].encode() self.bob.join_policy(label, alice_sig_pubkey) message_kit = UmbralMessageKit.from_bytes(data) data_source = Enrico.from_public_keys( verifying_key=data_source_public_key, policy_encrypting_key=policy_pubkey) retrieved_plaintexts = self.bob.retrieve( message_kit, label=label, enrico=data_source, alice_verifying_key=alice_sig_pubkey) retrieved_plaintexts = [ x.decode('utf-8') for x in retrieved_plaintexts ] return retrieved_plaintexts
def enrico_control_from_alice(federated_alice, random_policy_label): enrico = Enrico.from_alice(federated_alice, random_policy_label) enrico_control = enrico.make_wsgi_app() enrico_control.config['DEBUG'] = True enrico_control.config['TESTING'] = True yield enrico_control.test_client()
def ensure_correct_sender( self, enrico: Optional["Enrico"] = None, policy_encrypting_key: Optional[UmbralPublicKey] = None): """ Make sure that the sender of the message kit is set and corresponds to the given ``enrico``, or create it from the given ``policy_encrypting_key``. """ if self.sender: if enrico and self.sender != enrico: raise ValueError( f"Mismatched sender: the object has {self.sender}, provided {enrico}" ) elif enrico: self.sender = enrico elif self.sender_verifying_key and policy_encrypting_key: # Well, after all, this is all we *really* need. from nucypher.characters.lawful import Enrico self.sender = Enrico.from_public_keys( verifying_key=self.sender_verifying_key, policy_encrypting_key=policy_encrypting_key) else: raise ValueError( "No information provided to set the message kit sender. " "Need eiter `enrico` or `policy_encrypting_key` to be given.")
def reset(self, plaintext_passthrough=False): self.enrico = Enrico( policy_encrypting_key=enacted_blockchain_policy.public_key) self.messages = [] self.plaintexts = [] self.plaintext_passthrough = plaintext_passthrough return self(), self.enrico
def decrypt(self, bob, item_cid, pol, sig, lab): policy_pubkey = UmbralPublicKey.from_bytes(bytes.fromhex(pol)) alices_sig_pubkey = UmbralPublicKey.from_bytes(bytes.fromhex(sig)) label = lab.encode() dat = self.ipfs_gateway_api.cat(item_cid) doctor = bob doctor.join_policy(label, alices_sig_pubkey) data = msgpack.loads(dat, raw=False) message_kits = (UmbralMessageKit.from_bytes(k) for k in data['kits']) data_source = Enrico.from_public_keys( {SigningPower: data['data_source']}, policy_encrypting_key=policy_pubkey ) message_kit = next(message_kits) start = timer() retrieved_plaintexts = doctor.retrieve( label=label, message_kit=message_kit, data_source=data_source, alice_verifying_key=alices_sig_pubkey ) end = timer() plaintext = msgpack.loads(retrieved_plaintexts[0], raw=False) heart_rate = plaintext['heart_rate'] timestamp = maya.MayaDT(plaintext['timestamp']) terminal_size = shutil.get_terminal_size().columns max_width = min(terminal_size, 120) columns = max_width - 12 - 27 scale = columns / 40 retrieval_time = "Retrieval time: {:8.2f} ms".format(1000 * (end - start)) line = heart_rate# + " " + retrieval_time return line
def decrypt(self, label: bytes, message_kit: bytes) -> dict: """ Character control endpoint to allow Alice to decrypt her own data. """ from nucypher.characters.lawful import Enrico policy_encrypting_key = self.character.get_policy_encrypting_key_from_label(label) # TODO #846: May raise UnknownOpenSSLError and InvalidTag. message_kit = UmbralMessageKit.from_bytes(message_kit) enrico = Enrico.from_public_keys( verifying_key=message_kit.sender_verifying_key, policy_encrypting_key=policy_encrypting_key, label=label ) plaintexts = self.character.decrypt_message_kit( message_kit=message_kit, data_source=enrico, label=label ) response = {'cleartexts': plaintexts} return response
def retrieve(self, label: bytes, policy_encrypting_key: bytes, alice_verifying_key: bytes, message_kit: bytes, treasure_map: Union[bytes, str, 'TreasureMap'] = None): """ Character control endpoint for re-encrypting and decrypting policy data. """ from nucypher.characters.lawful import Enrico policy_encrypting_key = UmbralPublicKey.from_bytes( policy_encrypting_key) alice_verifying_key = UmbralPublicKey.from_bytes(alice_verifying_key) message_kit = UmbralMessageKit.from_bytes( message_kit ) # TODO #846: May raise UnknownOpenSSLError and InvalidTag. enrico = Enrico.from_public_keys( verifying_key=message_kit.sender_verifying_key, policy_encrypting_key=policy_encrypting_key, label=label) self.character.join_policy(label=label, alice_verifying_key=alice_verifying_key) plaintexts = self.character.retrieve( message_kit, enrico=enrico, alice_verifying_key=alice_verifying_key, label=label, treasure_map=treasure_map) response_data = {'cleartexts': plaintexts} return response_data
def _create_enrico(emitter, policy_encrypting_key): policy_encrypting_key = UmbralPublicKey.from_bytes( bytes.fromhex(policy_encrypting_key)) ENRICO = Enrico(policy_encrypting_key=policy_encrypting_key) ENRICO.controller.emitter = emitter # TODO: set it on object creation? Or not set at all? return ENRICO
def retrieve(self, label: bytes, policy_encrypting_key: bytes, alice_verifying_key: bytes, message_kit: bytes): """ Character control endpoint for re-encrypting and decrypting policy data. """ from nucypher.characters.lawful import Enrico policy_encrypting_key = UmbralPublicKey.from_bytes(policy_encrypting_key) alice_pubkey_sig = UmbralPublicKey.from_bytes(alice_verifying_key) message_kit = UmbralMessageKit.from_bytes(message_kit) # TODO: May raise UnknownOpenSSLError and InvalidTag. data_source = Enrico.from_public_keys({SigningPower: message_kit.sender_pubkey_sig}, policy_encrypting_key=policy_encrypting_key, label=label) self.bob.join_policy(label=label, alice_pubkey_sig=alice_pubkey_sig) plaintexts = self.bob.retrieve(message_kit=message_kit, data_source=data_source, alice_verifying_key=alice_pubkey_sig, label=label) response_data = {'cleartexts': plaintexts} return response_data
def test_blockchain_ursulas_reencrypt(blockchain_ursulas, blockchain_alice, blockchain_bob, policy_value): label = b'bbo' # TODO: Make sample selection buffer configurable - #1061 # Currently, it only supports N<=6, since for N=7, it tries to sample 11 ursulas due to wiggle room, # and blockchain_ursulas only contains 10. # For N >= 7 : NotEnoughBlockchainUrsulas: Cannot create policy with 7 arrangements: There are 10 active stakers, need at least 11. m = n = 6 expiration = maya.now() + datetime.timedelta(days=5) _policy = blockchain_alice.grant(bob=blockchain_bob, label=label, m=m, n=n, expiration=expiration, value=policy_value) enrico = Enrico.from_alice(blockchain_alice, label) message = b"Oh, this isn't even BO. This is beyond BO. It's BBO." message_kit, signature = enrico.encrypt_message(message) blockchain_bob.join_policy(label, bytes(blockchain_alice.stamp)) plaintext = blockchain_bob.retrieve(message_kit, enrico, blockchain_alice.stamp, label) assert plaintext[0] == message
def _create_enrico(emitter, policy_encrypting_key): policy_encrypting_key = UmbralPublicKey.from_bytes( bytes.fromhex(policy_encrypting_key)) ENRICO = Enrico(policy_encrypting_key=policy_encrypting_key) ENRICO.controller.emitter = emitter return ENRICO
def test_federated_alice_can_decrypt(federated_alice, federated_bob): """ Test that alice can decrypt data encrypted by an enrico for her own derived policy pubkey. """ # Setup the policy details threshold, shares = 2, 3 policy_end_datetime = maya.now() + datetime.timedelta(days=5) label = b"this_is_the_path_to_which_access_is_being_granted" policy = federated_alice.create_policy( bob=federated_bob, label=label, threshold=threshold, shares=shares, expiration=policy_end_datetime, ) enrico = Enrico.from_alice( federated_alice, policy.label, ) plaintext = b"this is the first thing i'm encrypting ever." # use the enrico to encrypt the message message_kit = enrico.encrypt_message(plaintext) # decrypt the data decrypted_data = federated_alice.decrypt_message_kit( label=policy.label, message_kit=message_kit, ) assert [plaintext] == decrypted_data
def test_blockchain_ursulas_reencrypt(blockchain_ursulas, blockchain_alice, blockchain_bob, policy_value): label = b'bbo' # TODO: Investigate issues with wiggle room and additional ursulas during sampling. See also #1061 and #1090 # 1 <= N <= 4 : OK, although for N=4 it can fail with very small probability (<1%) # M = N = 5: Fails with prob. ~66% --> Cannot create policy with 5 arrangements: Selection failed after 5 attempts # N == 6 : NotEnoughBlockchainUrsulas: Cannot create policy with 6 arrangements: Selection failed after 5 attempts # N >= 7 : NotEnoughBlockchainUrsulas: Cannot create policy with 7 arrangements: Cannot create policy with 7 arrangements: 10 stakers are available, need 11 (for wiggle room) m = n = 3 expiration = maya.now() + datetime.timedelta(days=5) _policy = blockchain_alice.grant(bob=blockchain_bob, label=label, m=m, n=n, expiration=expiration, value=policy_value) enrico = Enrico.from_alice(blockchain_alice, label) message = b"Oh, this isn't even BO. This is beyond BO. It's BBO." message_kit, signature = enrico.encrypt_message(message) blockchain_bob.join_policy(label, bytes(blockchain_alice.stamp)) plaintext = blockchain_bob.retrieve(message_kit, enrico, blockchain_alice.stamp, label) assert plaintext[0] == message
def encrypt_data(plain_text, datasource_filename): POLICY_FILENAME = "policy-metadata.json" POLICY_FILE = os.path.join( settings.BASE_DIR, 'nucypher_utils', 'nucypher_data', POLICY_FILENAME, ) with open(POLICY_FILE, 'rb') as fp: policy_pubkey_data = json.load(fp) policy_pubkey_string = policy_pubkey_data['policy_pubkey'] policy_pubkey_bytes = unhexlify(policy_pubkey_string) policy_pubkey = keys.UmbralPublicKey.from_bytes(policy_pubkey_bytes) data_source = Enrico(policy_encrypting_key=policy_pubkey) data_source_public_key = bytes(data_source.stamp) plain_text = bytes(plain_text, 'utf-8') message_kit, _signature = data_source.encrypt_message(plain_text) kit_bytes = message_kit.to_bytes() kit = kit_bytes data = { 'data_source_public_key': data_source_public_key, 'kits': kit, } # data souce pub key naming convention: # author_name-article_title-article_id-datasource-pubkey.msgpack DATA_SOURCE_DIR = os.path.join( settings.BASE_DIR, 'nucypher_utils', 'nucypher_data', ) DATA_SOURCE_FILE_NAME = datasource_filename with open(os.path.join(DATA_SOURCE_DIR, DATA_SOURCE_FILE_NAME), "wb") as file: msgpack.dump(data, file, use_bin_type=True) return kit_bytes
def test_alice_can_decrypt(federated_alice): label = b"boring test label" policy_pubkey = federated_alice.get_policy_pubkey_from_label(label) enrico = Enrico(policy_encrypting_key=policy_pubkey) message = b"boring test message" message_kit, signature = enrico.encrypt_message(message=message) # Interesting thing: if Alice wants to decrypt, she needs to provide the label directly. cleartext = federated_alice.verify_from(stranger=enrico, message_kit=message_kit, signature=signature, decrypt=True, label=label) assert cleartext == message
def mario_box_cli(plaintext_dir, alice_config, label, outfile): # Derive Policy Encrypting Key alice_configuration = AliceConfiguration.from_configuration_file( filepath=alice_config) alice = make_cli_character(character_config=alice_configuration) alice_signing_key = alice.public_keys(SigningPower) policy_encrypting_key = alice.get_policy_encrypting_key_from_label( label=label.encode()) policy_encrypting_key_hex = bytes(policy_encrypting_key).hex() output = list() paths = list(plaintext_dir.iterdir()) click.secho( f"Encrypting {len(paths)} files for policy {policy_encrypting_key_hex}", fg='blue') with click.progressbar(paths) as bar: for path in bar: filepath = Path(plaintext_dir, path) with open(filepath, 'rb') as file: plaintext = file.read() encoded_plaintext = base64.b64encode(plaintext) enrico = Enrico(policy_encrypting_key=policy_encrypting_key) message_kit = enrico.encrypt_message( plaintext=encoded_plaintext) base64_message_kit = base64.b64encode( bytes(message_kit)).decode() # Collect Bob Retrieve JSON Requests retrieve_payload = { 'label': label, 'policy-encrypting-key': policy_encrypting_key_hex, 'alice-verifying-key': bytes(alice_signing_key).hex(), 'message-kit': base64_message_kit } output.append(retrieve_payload) if not outfile: outfile = f'{policy_encrypting_key_hex}.json' with open(outfile, 'w') as file: file.write(json.dumps(output, indent=2)) click.secho(f"Successfully wrote output to {outfile}", fg='green')
def encrypt_data(self, plaintext): """ Encrypt data Args: plaintext (str): plaintext that should be encrypted Returns: label, data_source_public_key, data (bytes, bytes, byes): tuple containing label for the policy, data source public_key & encrypted data """ label = ("policy️-" + os.urandom(8).hex()).encode() policy_pubkey = self.alice.get_policy_encrypting_key_from_label(label) data_source = Enrico(policy_encrypting_key=policy_pubkey) data_source_public_key = bytes(data_source.stamp) message, _signature = data_source.encrypt_message( plaintext.encode("utf-8")) data = message.to_bytes() return label, data_source_public_key, data
def encrypt_track(policy_pubkey, file_path): data_source = Enrico(policy_encrypting_key=policy_pubkey) data_source_public_key = bytes(data_source.stamp) print(file_path) with open(file_path, "rb") as f: plaintext = f.read() ciphertext, signature = data_source.encrypt_message(plaintext) print("Signature", signature) data = { 'track_segment_data': ciphertext.to_bytes(), 'data_source': data_source_public_key } with open(file_path + '_encrypted', "wb") as f: msgpack.dump(data, f, use_bin_type=True) return True
def from_channel(cls, channel: Channel, data: bytes) -> object: ''' Create EncryptedDataPackage from Channel & data. In other words it encrypts data usign Channel settings :param channel: Channel instance :param data: data to be encrypted :return: EncryptedDataPackage instance ''' label_bytes = channel.label_bytes policy_pub_key_object = UmbralPublicKey.from_bytes( channel.policy_pubkey_bytes) data_source = Enrico(policy_encrypting_key=policy_pub_key_object) data_source_pubkey_bytes = bytes(data_source.stamp) message_kit, _signature = data_source.encrypt_message(data) kit_bytes = message_kit.to_bytes() return EncryptedDataPackage( alice_pubkey_bytes=channel.alice_pubkey_bytes, data_source_pubkey_bytes=data_source_pubkey_bytes, kit_bytes=kit_bytes, label_bytes=label_bytes, policy_pubkey_bytes=channel.policy_pubkey_bytes)
def generate_heart_rate_samples(policy_pubkey, samples: int = 500, save_as_file: bool = False): data_source = Enrico(policy_encrypting_key=policy_pubkey) data_source_public_key = bytes(data_source.stamp) heart_rate = 80 now = time.time() kits = list() for _ in range(samples): # Simulated heart rate data # Normal resting heart rate for adults: between 60 to 100 BPM heart_rate = random.randint(max(60, heart_rate - 5), min(100, heart_rate + 5)) now += 3 heart_rate_data = { 'heart_rate': heart_rate, 'timestamp': now, } plaintext = msgpack.dumps(heart_rate_data, use_bin_type=True) message_kit = data_source.encrypt_message(plaintext) kit_bytes = bytes(message_kit) kits.append(kit_bytes) data = { 'data_source': data_source_public_key, 'kits': kits, } if save_as_file: with open(HEART_DATA_FILENAME, "wb") as file: msgpack.dump(data, file, use_bin_type=True) return data