Ejemplo n.º 1
0
def initialize_alice():
    ursula = Ursula.from_seed_and_stake_info(seed_uri=SEEDNODE_URI,
                                         federated_only=True,
                                         minimum_stake=0)

    # If anything fails, let's create Alicia from scratch
    # Remove previous demo files and create new ones
    shutil.rmtree(TEMP_ALICE_DIR, ignore_errors=True)
    
    alice_config = AliceConfiguration(
        config_root=os.path.join(TEMP_ALICE_DIR),
        domains={TEMPORARY_DOMAIN},
        known_nodes={ursula},
        start_learning_now=False,
        federated_only=True,
        learn_on_same_thread=True,
    )

    alice_config.initialize(password=passphrase)
    alice_config.keyring.unlock(password=passphrase)
    
    # We will save Alicia's config to a file for later use
    alice_config_file = alice_config.to_configuration_file()
    
    with open(os.path.join(TEMP_ALICE_DIR, 'alice.config.json'), 'w') as f:
        f.write(open(alice_config_file).read())
    
    alicia = alice_config.produce()
    
    # Let's get to learn about the NuCypher network
    alicia.start_learning_loop(now=True)
    return alicia, alice_config_file
Ejemplo n.º 2
0
def createGenericAlicia(passphrase):
    print('createGenericAlicia')
    TEMP_ALICE_DIR = os.path.join('/', 'tmp', 'zkDonationFlaskApp')
    shutil.rmtree(TEMP_ALICE_DIR, ignore_errors=True)

    ursula = Ursula.from_seed_and_stake_info(seed_uri=SEEDNODE_URI,
                                             federated_only=True,
                                             minimum_stake=0)

    alice_config = AliceConfiguration(
        config_root=os.path.join(TEMP_ALICE_DIR),
        domains={TEMPORARY_DOMAIN},
        known_nodes={ursula},
        start_learning_now=False,
        federated_only=True,
        learn_on_same_thread=True,
    )

    alice_config.initialize(password=passphrase)

    alice_config.keyring.unlock(password=passphrase)
    alicia = alice_config.produce()

    alice_config.to_configuration_file()

    alicia.start_learning_loop(now=True)

    return alicia
Ejemplo n.º 3
0
def highperf_mocked_alice(fleet_of_highperf_mocked_ursulas):
    config = AliceConfiguration(dev_mode=True,
                                domains={TEMPORARY_DOMAIN},
                                network_middleware=MockRestMiddlewareForLargeFleetTests(),
                                federated_only=True,
                                abort_on_learning_error=True,
                                save_metadata=False,
                                reload_metadata=False)

    with mock_cert_storage, mock_verify_node, mock_record_fleet_state, mock_message_verification, mock_keep_learning:
        alice = config.produce(known_nodes=list(fleet_of_highperf_mocked_ursulas)[:1])
    return alice
Ejemplo n.º 4
0
    def create_new_user(self, name, password):
        print("create_new_user")
        passphrase = password
        direco = "accounts/"+ name
#         alice_config = AliceConfiguration(
#             config_root=os.path.join(direco),
#             is_me=True, known_nodes={self.ursula}, start_learning_now=True,
#             federated_only=True, learn_on_same_thread=True,
#         )
#         alice_config.initialize(password=passphrase)
#         alice_config.keyring.unlock(password=passphrase)
#         alice_config_file = alice_config.to_configuration_file()
        alice_config = AliceConfiguration(
            config_root=os.path.join(direco),
            # is_me=True,
            known_nodes={self.ursula},
            start_learning_now=False,
            federated_only=True,
            learn_on_same_thread=True,
        )
        alice_config.initialize(password=passphrase)
        alice_config.keyring.unlock(password=passphrase)
        # print(dir(alice_config.keyring))
        alice = alice_config.produce()
        alice_config_file = alice_config.to_configuration_file()
        alice.start_learning_loop(now=True)

        
        enc_privkey = UmbralPrivateKey.gen_key()
        sig_privkey = UmbralPrivateKey.gen_key()

        doctor_privkeys = {
            'enc': enc_privkey.to_bytes().hex(),
            'sig': sig_privkey.to_bytes().hex(),
        }

        DOCTOR_PUBLIC_JSON =  direco + '/recipent.public.json'
        DOCTOR_PRIVATE_JSON = direco + '/recipent.private.json'

        with open(DOCTOR_PRIVATE_JSON, 'w') as f:
            json.dump(doctor_privkeys, f)

        enc_pubkey = enc_privkey.get_pubkey()
        sig_pubkey = sig_privkey.get_pubkey()
        doctor_pubkeys = {
            'enc': enc_pubkey.to_bytes().hex(),
            'sig': sig_pubkey.to_bytes().hex()
        }
        with open(DOCTOR_PUBLIC_JSON, 'w') as f:
            json.dump(doctor_pubkeys, f)
        # print(dir(alice))
        return alice
Ejemplo n.º 5
0
def highperf_mocked_alice(fleet_of_highperf_mocked_ursulas):
    config = AliceConfiguration(dev_mode=True,
                                domain=TEMPORARY_DOMAIN,
                                network_middleware=MockRestMiddlewareForLargeFleetTests(),
                                federated_only=True,
                                abort_on_learning_error=True,
                                save_metadata=False,
                                reload_metadata=False)

    with mock_cert_storage, mock_verify_node, mock_record_fleet_state, mock_message_verification, mock_keep_learning:
        alice = config.produce(known_nodes=list(fleet_of_highperf_mocked_ursulas)[:1])
    yield alice
    # TODO: Where does this really, truly belong?
    alice._learning_task.stop()
Ejemplo n.º 6
0
def make_alice(known_nodes: Optional[Set[Ursula]] = None):
    """Initializes a new 'persistent alice configuration' for grant metrics collection."""
    alice_config = AliceConfiguration(provider_uri=ETHEREUM_PROVIDER_URI,
                                      checksum_address=ALICE_ADDRESS,
                                      signer_uri=f'keystore://{SIGNER_URI}',
                                      config_root=os.path.join(TEMP_ALICE_DIR),
                                      domain=DOMAIN,
                                      known_nodes=known_nodes,
                                      start_learning_now=False,
                                      federated_only=False,
                                      learn_on_same_thread=True,
                                      gas_strategy=GAS_STRATEGY)

    alice_config.initialize(password=INSECURE_PASSWORD)
    alice_config.keyring.unlock(password=INSECURE_PASSWORD)
    alice = alice_config.produce(client_password=SIGNER_PASSWORD)
    alice.start_learning_loop(now=True)
    return alice
Ejemplo n.º 7
0
    def _get_alice(self):
        # Gets an Alice instance
        #print('Getting an Alice')
        try:  # If we had an existing Alicia in disk, let's get it from there
            alice_config_file = os.path.join(self.TEMP_ALICE_DIR,
                                             "config_root", "alice.config")
            new_alice_config = AliceConfiguration.from_configuration_file(
                filepath=alice_config_file,
                known_nodes=[self.ursula],
                network_middleware=RestMiddleware(),
                start_learning_now=False,
                save_metadata=False,
            )
            #new_alice_config.keyring.unlock(password=self.passphrase)
            alicia = new_alice_config.produce()
        except:  # If anything fails, let's create Alicia from scratch
            # Remove previous demo files and create new ones

            #print("Creating ALICE")

            shutil.rmtree(self.TEMP_ALICE_DIR, ignore_errors=True)
            os.mkdir(self.TEMP_ALICE_DIR)
            os.mkdir(self.TEMP_ALICE_URSULA_DIR)

            alice_config = AliceConfiguration(
                config_root=os.path.join(self.TEMP_ALICE_DIR, "config_root"),
                is_me=True,
                known_nodes=[self.ursula],
                start_learning_now=False,
                federated_only=True,
                learn_on_same_thread=True,
            )
            alice_config.initialize(password=self.passphrase)
            alice_config.keyring.unlock(password=self.passphrase)
            alicia = alice_config.produce()

            # We will save Alicia's config to a file for later use
            alice_config_file = alice_config.to_configuration_file()

        # Let's get to learn about the NuCypher network
        alicia.start_learning_loop(now=True)

        return alicia
Ejemplo n.º 8
0
def generateKeys():

    # Fetch JSON from request
    print('####')
    print(request.data)
    json_data = json.loads(request.data.decode('utf-8'))

    # Fetch username and password

    username = json_data['username']
    print (username, "username")
    password = json_data['password']

    # directory to store alice keys
    ALICE_DIR = os.path.join(os.getcwd() , 'alice/' + username)
    print(ALICE_DIR)


    alice_config = AliceConfiguration(
        domains={'TEMPORARY_DOMAIN'},
        config_root=os.path.join(ALICE_DIR),
        is_me=True,
        known_nodes={ursula},
        start_learning_now=False,
        federated_only=True,
        learn_on_same_thread=True
    )

    alice_config.initialize(password=password)
    alice_config.keyring.unlock(password=password)
    file = alice_config.to_configuration_file()
    alicia = alice_config.produce()
    alicia.start_learning_loop(now=True)

    data = {}
    data['alice'] = file
    data['bob'] = generate_doctor_keys(username=username);

    print(data)

    return jsonify(data)
Ejemplo n.º 9
0
                                             federated_only=True,
                                             minimum_stake=0)

    alice_config = AliceConfiguration(
        config_root=os.path.join(TEMP_ALICE_DIR),
        is_me=True,
        known_nodes={ursula},
        start_learning_now=False,
        federated_only=True,
        learn_on_same_thread=True,
    )

    alice_config.initialize(password=passphrase)

    alice_config.keyring.unlock(password=passphrase)
    alicia = alice_config.produce()

    # We will save Alicia's config to a file for later use
    alice_config_file = alice_config.to_configuration_file()

# Let's get to learn about the NuCypher network
alicia.start_learning_loop(now=True)

# At this point, Alicia is fully operational and can create policies.
# The Policy Label is a bytestring that categorizes the data that Alicia wants to share.
# Note: we add some random chars to create different policies, only for demonstration purposes
label = "heart-data-❤️-" + os.urandom(4).hex()
label = label.encode()

# Alicia can create the public key associated to the policy label,
# even before creating any associated policy.
Ejemplo n.º 10
0
def initialize_alice_policy_pubkey(
        alice_encryption_password: str = "TEST_ALICE_PASSWORD"):
    """
    Takes in alice's encryption password as input and generates and
    stores the policy pubkey.
    """

    globalLogPublisher.addObserver(SimpleObserver())
    NUCYPHER_DATA_DIR = os.path.join(
        settings.BASE_DIR,
        'nucypher_utils',
        'nucypher_data',
    )
    if not os.path.exists(NUCYPHER_DATA_DIR):
        os.mkdir(NUCYPHER_DATA_DIR)

    if os.listdir(NUCYPHER_DATA_DIR):
        print("data directory not clean...Cleaning...")
        shutil.rmtree(NUCYPHER_DATA_DIR)
        if not os.path.exists(NUCYPHER_DATA_DIR):
            os.mkdir(NUCYPHER_DATA_DIR)

    if os.listdir(NUCYPHER_DATA_DIR):
        print("Data Directory Cleaned")

    ALICE_CONFIG_DIR = os.path.join(settings.BASE_DIR, 'nucypher_utils',
                                    'nucypher_data', 'nucypher_char_configs',
                                    'stridon-demo-alice')

    # We expect the url of the seednode as the first argument.
    SEEDNODE_URL = 'localhost:11500'

    POLICY_FILENAME = "policy-metadata.json"

    ursula = Ursula.from_seed_and_stake_info(seed_uri=SEEDNODE_URL,
                                             federated_only=True,
                                             minimum_stake=0)

    passphrase = alice_encryption_password

    alice_config = AliceConfiguration(
        config_root=os.path.join(ALICE_CONFIG_DIR),
        is_me=True,
        known_nodes={ursula},
        start_learning_now=False,
        federated_only=True,
        learn_on_same_thread=True,
    )

    alice_config.initialize(password=passphrase)
    alice_config.keyring.unlock(password=passphrase)
    alice_config_file = alice_config.to_configuration_file()
    print(alice_config_file)

    alice = alice_config.produce()
    label = "stridon-premium-service"
    label = label.encode()

    policy_pubkey = alice.get_policy_pubkey_from_label(label)

    print("The policy public key for label '{}' is {}".format(
        label.decode("utf-8"),
        policy_pubkey.to_bytes().hex()))

    policy_json = {
        "policy_pubkey": policy_pubkey.to_bytes().hex(),
    }

    POLICY_FILE = os.path.join(
        os.getcwd(),
        'nucypher_utils',
        'nucypher_data',
        POLICY_FILENAME,
    )

    with open(POLICY_FILE, 'w') as f:
        json.dump(policy_json, f)
    from nucypher.crypto.powers import SigningPower, DecryptingPower
    print(alice.public_keys(SigningPower))
    print(alice.public_keys(DecryptingPower))
Ejemplo n.º 11
0
def alicia_encrypt(data_fields, pid):
    POLICY_FILENAME = "policy-metadata.json"
    globalLogPublisher.addObserver(SimpleObserver())
    TEMP_ALICE_DIR = "alicia-files".format(
        os.path.dirname(os.path.abspath(__file__)))
    SEEDNODE_URL = 'localhost:11500'

    passphrase = "TEST_ALICIA_INSECURE_DEVELOPMENT_PASSWORD"
    try:
        alice_config_file = os.path.join(TEMP_ALICE_DIR, "alice.config")
        new_alice_config = AliceConfiguration.from_configuration_file(
            filepath=alice_config_file,
            network_middleware=RestMiddleware(),
            start_learning_now=False,
            save_metadata=False,
        )
        alicia = new_alice_config(passphrase=passphrase)

    except:
        shutil.rmtree(TEMP_ALICE_DIR, ignore_errors=True)
        ursula = Ursula.from_seed_and_stake_info(seed_uri=SEEDNODE_URL,
                                                 federated_only=True,
                                                 minimum_stake=0)
        alice_config = AliceConfiguration(
            config_root=os.path.join(TEMP_ALICE_DIR),
            is_me=True,
            known_nodes={ursula},
            start_learning_now=False,
            federated_only=True,
            learn_on_same_thread=True,
        )

        alice_config.initialize(password=passphrase)

        alice_config.keyring.unlock(password=passphrase)
        alicia = alice_config.produce()
        alice_config_file = alice_config.to_configuration_file()

    alicia.start_learning_loop(now=True)
    label = "doctor"
    label = label.encode()
    policy_pubkey = alicia.get_policy_pubkey_from_label(label)

    print("The policy public key for "
          "label '{}' is {}".format(label.decode("utf-8"),
                                    policy_pubkey.to_bytes().hex()))

    import data_ipfs
    res = data_ipfs.encrypt_patient_data(policy_pubkey,
                                         data_fields,
                                         pid,
                                         label=label,
                                         save_as_file=True)
    print(res)

    from doctor_keys import get_doctor_pubkeys
    doctor_pubkeys = get_doctor_pubkeys()

    powers_and_material = {
        DecryptingPower: doctor_pubkeys['enc'],
        SigningPower: doctor_pubkeys['sig']
    }

    doctor_strange = Bob.from_public_keys(
        powers_and_material=powers_and_material, federated_only=True)

    policy_end_datetime = maya.now() + datetime.timedelta(days=5)

    m, n = 2, 3
    print("Creating access policy for the Doctor...")
    policy = alicia.grant(bob=doctor_strange,
                          label=label,
                          m=m,
                          n=n,
                          expiration=policy_end_datetime)
    print("Done!")

    policy_info = {
        "policy_pubkey": policy.public_key.to_bytes().hex(),
        "alice_sig_pubkey": bytes(alicia.stamp).hex(),
        "label": label.decode("utf-8"),
    }

    filename = POLICY_FILENAME
    with open(filename, 'w') as f:
        json.dump(policy_info, f)

    return res
                                         federated_only=True,
                                         minimum_stake=0)

arjun_config = AliceConfiguration(
    config_root=os.path.join(TEMP_ARJUN_DIR),
    is_me=True,
    known_nodes={ursula},
    start_learning_now=False,
    federated_only=True,
    learn_on_same_thread=True,
)

arjun_config.initialize(password=passphrase)

arjun_config.keyring.unlock(password=passphrase)
arjun = arjun_config.produce()

# We will save Alicia's config to a file for later use
arjun_config_file = arjun_config.to_configuration_file()

# Let's get to learn about the NuCypher network
arjun.start_learning_loop(now=True)

# At this point, Alicia is fully operational and can create policies.
# The Policy Label is a bytestring that categorizes the data that Alicia wants to share.
# Note: we add some random chars to create different policies, only for demonstration purposes
label = "chat" + os.urandom(4).hex()
label = label.encode()

# Alicia can create the public key associated to the policy label,
# even before creating any associated policy.
Ejemplo n.º 13
0
                                         federated_only=True,
                                         minimum_stake=0)

alice_config = AliceConfiguration(
    config_root=os.path.join(TEMP_ALICE_DIR),
    is_me=True,
    known_nodes={ursula},
    start_learning_now=False,
    federated_only=True,
    learn_on_same_thread=True,
)

alice_config.initialize(password=passphrase)

alice_config.keyring.unlock(password=passphrase)
alice = alice_config.produce()

# We will save Alicia's config to a file for later use
alice_config_file = alice_config.to_configuration_file()

# Let's get to learn about the NuCypher network
alice.start_learning_loop(now=True)

# At this point, Alicia is fully operational and can create policies.
# The Policy Label is a bytestring that categorizes the data that Alicia wants to share.
# Note: we add some random chars to create different policies, only for demonstration purposes
label = "chat" + os.urandom(4).hex()
label = label.encode()

# Alicia can create the public key associated to the policy label,
# even before creating any associated policy.
Ejemplo n.º 14
0
class KMS:
    def __init__(self,
                 ursula_url,
                 dir_name,
                 passphrase,
                 ipfs_addr='',
                 arweave_wallet_file_path='',
                 federated_only=True,
                 signer_uri='',
                 checksum_address=None,
                 client_password=None,
                 provider_uri='',
                 domain=TEMPORARY_DOMAIN):
        """
        Args:
            ursula_url (str): ursula url e.g. localhost:11500
            dir_name (str): dir_name where account files will be stored in tmp directory
            passphrase (str): passphrase for account
            ipfs_addr (str): ipfs addr (required only if you want to store data in ipfs)
            arweave_wallet_file_path (str): arweave wallet file path (required only if you want to store
                                            data in arweave)
            federated_only (bool): Whether federated mode should be used
            signer_uri (str): signer uri for ethereum transaction
                            https://docs.nucypher.com/en/latest/guides/ethereum_node.html#external-transaction-signing
            checksum_address (str): Ethereum address
            client_password (str): Password for ethereum keystore. Required only if signer_uri is keystore://{path}
            provider_uri (str): geth or infura https uri
            domain (str): nucypher network name e.g. lynx for nucypher testnet and mainnet for nucypher mainnet
        """
        self.__client_password = client_password
        self.federated_only = federated_only
        self.ursula_url = ursula_url
        self.ursula = Ursula.from_seed_and_stake_info(
            seed_uri=self.ursula_url,
            federated_only=self.federated_only,
            minimum_stake=0)
        self.arweave_wallet = None
        if arweave_wallet_file_path:
            self.arweave_wallet = arweave.Wallet(arweave_wallet_file_path)
        self.ipfs = None
        if ipfs_addr:
            self.ipfs = ipfshttpclient.connect(ipfs_addr)
        self.temp_dir = os.path.join('/', 'tmp', dir_name)
        self.alice_config = AliceConfiguration(
            provider_uri=provider_uri,
            checksum_address=checksum_address,
            signer_uri=signer_uri,
            config_root=os.path.join(self.temp_dir),
            domain=domain,
            known_nodes={self.ursula},
            start_learning_now=False,
            federated_only=self.federated_only,
            learn_on_same_thread=True)
        try:
            if os.path.exists(os.path.join(self.temp_dir, "alice.json")):
                raise ExistingKeyringError()
            self.alice_config.initialize(password=passphrase)
        except ExistingKeyringError:
            self.alice_config = AliceConfiguration.from_configuration_file(
                filepath=os.path.join(self.temp_dir, "alice.json"),
                known_nodes={self.ursula},
                start_learning_now=False)
            self.alice_config.attach_keyring()
        self.alice_config.keyring.unlock(password=passphrase)
        signer = Signer.from_signer_uri(signer_uri) if signer_uri else None
        if signer:
            signer.unlock_account(account=checksum_address,
                                  password=client_password)
        self.alice = self.alice_config.produce(signer=signer)
        try:
            self.alice_config_file = self.alice_config.to_configuration_file()
        except FileExistsError:
            pass
        self.alice.start_learning_loop(now=True)
        self.privkeys, self.pubkeys = fetch_keys(path=self.temp_dir)
        bob_enc_keypair = DecryptingKeypair(private_key=self.privkeys["enc"])
        bob_sig_keypair = SigningKeypair(private_key=self.privkeys["sig"])
        enc_power = DecryptingPower(keypair=bob_enc_keypair)
        sig_power = SigningPower(keypair=bob_sig_keypair)
        power_ups = [enc_power, sig_power]
        self.bob = Bob(domain=domain,
                       federated_only=self.federated_only,
                       crypto_power_ups=power_ups,
                       start_learning_now=True,
                       abort_on_learning_error=True,
                       known_nodes=[self.ursula],
                       save_metadata=False,
                       network_middleware=RestMiddleware(),
                       provider_uri=provider_uri)

    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 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 share_data_access(self,
                          pubkeys,
                          label,
                          days=5,
                          m=1,
                          n=1,
                          rate=Web3.toWei(50, 'gwei')):
        """
        Share data access based on public keys

        Args:
            pubkeys (dict): public keys dict containing sig and enc keys
            label (bytes): label for the policy
            days (int): days for which the access should be granted
            m (int): Minimum number of kfrags needed to activate a Capsule
            n (int): Total number of kfrags to generate
            rate (int): rate in wei

        Returns:
            policy_info (dict): dict containing policy_pubkey, alice_sig_pubkey and label keys
        """
        bob = Bob.from_public_keys(verifying_key=pubkeys['sig'],
                                   encrypting_key=pubkeys['enc'],
                                   federated_only=self.federated_only)
        # Policy expiration date
        policy_end_datetime = maya.now() + datetime.timedelta(days=days)
        power_ups = self.alice._crypto_power._CryptoPower__power_ups
        for key, power_up in power_ups.items():
            self.alice._crypto_power.consume_power_up(
                power_up, password=self.__client_password)
        policy = self.alice.grant(bob=bob,
                                  label=label,
                                  m=m,
                                  n=n,
                                  expiration=policy_end_datetime,
                                  rate=rate)
        policy_info = {
            "policy_pubkey": policy.public_key.to_bytes().hex(),
            "alice_sig_pubkey": bytes(self.alice.stamp).hex(),
            "label": label.decode("utf-8"),
        }
        return policy_info

    def upload_data(self, plaintext, storage):
        """
        Upload data to the selected storage

        Args:
            plaintext (str): plaintext
            storage (str): storage layer e.g. ipfs, arweave, skynet, etc.

        Returns:
           label, data_source_public_key, hash_key (bytes, bytes, str): tuple containing policy label,
                                                                         data source public key and hash_key
        """
        label, data_source_public_key, data = self.encrypt_data(
            plaintext=plaintext)
        if storage == "ipfs":
            hash_key = self.ipfs.add_bytes(data)
        elif storage == "arweave":
            transaction = arweave.Transaction(self.arweave_wallet, data=data)
            transaction.sign()
            transaction.send()
            hash_key = transaction.id
        elif storage == "skynet":
            file_name = '/tmp/{}.txt'.format(
                random.randint(100000000000, 999999999999))
            file = open(file_name, 'wb')
            file.write(data)
            file.close()
            skynet_client = skynet.SkynetClient()
            hash_key = skynet_client.upload_file(file_name)
        else:
            raise ValueError("invalid storage layer")
        return label, data_source_public_key, hash_key

    @staticmethod
    def get_shareable_code(hash_key, data_source_public_key, policy_info,
                           storage):
        """
        Get shareable code to fetch the secret which can be shared easily

        Args:
             hash_key (str): storage layer hash key
             data_source_public_key (bytes): data source public key
             policy_info (dict): dict containing policy_pubkey, alice_sig_pubkey and label keys
             storage (str): storage layer e.g. ipfs, arweave, skynet, etc.

        Returns:
             shareable_code (str): shareable code
        """
        data = {
            "hash": hash_key,
            "data_source_public_key": data_source_public_key.hex(),
            "policy_info": policy_info,
            "storage": storage
        }
        return base64.b64encode(
            json.dumps(data,
                       separators=(',', ':')).encode("utf-8")).decode('utf-8')

    def fetch_data(self, shareable_code, storage):
        """
        Fetch data from the selected storage and decrypt it

        Args:
            shareable_code (str): shareable code
            storage (str): storage layer e.g. ipfs, arweave, skynet, etc.

        Returns:
            retrieved_plaintexts (list): list of str
        """
        meta_data = json.loads(
            base64.b64decode(shareable_code.encode('utf-8')).decode('utf-8'))
        data_source_public_key = meta_data['data_source_public_key']
        hash_key = meta_data['hash']
        if storage == "ipfs":
            data = self.ipfs.cat(hash_key)
        elif storage == "arweave":
            transaction = arweave.Transaction(self.arweave_wallet, id=hash_key)
            transaction.get_data()
            data = transaction.data
            if data == b'':
                raise ValueError(
                    "Transaction not found. Wait for some more time")
        elif storage == "skynet":
            file_name = '/tmp/{}.txt'.format(
                random.randint(100000000000, 999999999999))
            skynet_client = skynet.SkynetClient()
            skynet_client.download_file(file_name, hash_key)
            file = open(file_name, 'rb')
            data = file.read()
            file.close()
        else:
            raise ValueError("invalid storage layer")
        data_source_public_key = bytes.fromhex(data_source_public_key)
        policy_info = meta_data["policy_info"]
        return self.decrypt_data(data_source_public_key=data_source_public_key,
                                 data=data,
                                 policy_info=policy_info)