Example #1
0
def test_keying_material_serialization():
    umbral_keying_material = UmbralKeyingMaterial()

    encoded_key = umbral_keying_material.to_bytes()

    decoded_key = UmbralKeyingMaterial.from_bytes(encoded_key)
    assert umbral_keying_material.keying_material == decoded_key.keying_material
Example #2
0
 def __init__(self,
              keying_material: Optional[bytes] = None,
              password: Optional[bytes] = None) -> None:
     if keying_material is None:
         self.__umbral_keying_material = UmbralKeyingMaterial()
     else:
         self.__umbral_keying_material = UmbralKeyingMaterial.from_bytes(key_bytes=keying_material,
                                                                         password=password)
Example #3
0
def test_keying_material_serialization():
    umbral_keying_material = UmbralKeyingMaterial()

    encoded_keying_material = umbral_keying_material.to_bytes()

    decoded_keying_material = UmbralKeyingMaterial.from_bytes(encoded_keying_material)

    label = os.urandom(32)
    privkey_bytes = umbral_keying_material.derive_privkey_by_label(label).to_bytes()
    assert privkey_bytes == decoded_keying_material.derive_privkey_by_label(label).to_bytes()
Example #4
0
def test_keying_material_serialization_with_encryption():
    umbral_keying_material = UmbralKeyingMaterial()

    insecure_cost = 15  # This is deliberately insecure, just to make the tests faster
    encoded_key = umbral_keying_material.to_bytes(password=b'test',
                                                  _scrypt_cost=insecure_cost)

    decoded_key = UmbralKeyingMaterial.from_bytes(encoded_key,
                                                  password=b'test',
                                                  _scrypt_cost=insecure_cost)

    assert umbral_keying_material.keying_material == decoded_key.keying_material
Example #5
0
def test_keying_material_serialization_with_encryption():
    umbral_keying_material = UmbralKeyingMaterial()

    insecure_cost = 15  # This is deliberately insecure, just to make the tests faster
    encoded_keying_material = umbral_keying_material.to_bytes(password=b'test',
                                                              _scrypt_cost=insecure_cost)

    decoded_keying_material = UmbralKeyingMaterial.from_bytes(encoded_keying_material,
                                                              password=b'test',
                                                              _scrypt_cost=insecure_cost)

    label = os.urandom(32)
    privkey_bytes = umbral_keying_material.derive_privkey_by_label(label).to_bytes()
    assert privkey_bytes == decoded_keying_material.derive_privkey_by_label(label).to_bytes()
Example #6
0
    def create_policy(self, label: bytes, alice_privkey: UmbralPrivateKey,
                      bob_pubkey: UmbralPublicKey, policy_expiration, m: int,
                      n: int):
        """
        Create a Policy with Alice granting Bob access to `label` DataSource

        :param label: A label to represent the policies data
        :param alice_privkey: Alice's private key
        :param bob_pubkey: Bob's public key
        :param policy_expiration: Datetime of policy expiration duration
        :param m: Minimum number of KFrags needed to rebuild ciphertext
        :param n: Total number of rekey shares to generate

        :return: The policy granted to Bob
        """
        # This is not how this should be implemented, but I am still figuring out
        # the keying material and why it is randomly generated when a character is
        # initialized, instead of being derived from the keys like the other powers
        # or explained how it should be stored.
        d = DelegatingPower()
        d.umbral_keying_material = UmbralKeyingMaterial.from_bytes(
            alice_privkey.to_bytes() + alice_privkey.get_pubkey().to_bytes())

        # Initialize Alice
        ALICE = Alice(
            crypto_power_ups=[
                SigningPower(keypair=SigningKeypair(alice_privkey)),
                EncryptingPower(keypair=EncryptingKeypair(alice_privkey)),
                # DelegatingPower
                d
            ],
            network_middleware=RestMiddleware(),
            known_nodes=(self.ursula, ),
            federated_only=True,
            always_be_learning=True)

        # Initialize Bob
        BOB = Bob(crypto_power_ups=[
            SigningPower(pubkey=bob_pubkey),
            EncryptingPower(pubkey=bob_pubkey)
        ],
                  known_nodes=(self.ursula, ),
                  federated_only=True,
                  always_be_learning=True)

        # Alice grants a policy for Bob
        policy = ALICE.grant(BOB,
                             label,
                             m=m,
                             n=n,
                             expiration=policy_expiration)

        return policy
Example #7
0
def test_derive_key_from_label():
    umbral_keying_material = UmbralKeyingMaterial()

    label = b"my_healthcare_information"

    priv_key1 = umbral_keying_material.derive_privkey_by_label(label)
    assert type(priv_key1) == UmbralPrivateKey

    pub_key1 = priv_key1.get_pubkey()
    assert type(pub_key1) == UmbralPublicKey

    # Check that key derivation is reproducible
    priv_key2 = umbral_keying_material.derive_privkey_by_label(label)
    pub_key2 = priv_key2.get_pubkey()
    assert priv_key1.bn_key == priv_key2.bn_key
    assert pub_key1 == pub_key2

    # A salt can be used too, but of course it affects the derived key
    salt = b"optional, randomly generated salt"
    priv_key3 = umbral_keying_material.derive_privkey_by_label(label, salt=salt)
    assert priv_key3.bn_key != priv_key1.bn_key

    # Different labels on the same master secret create different keys
    label = b"my_tax_information"
    priv_key4 = umbral_keying_material.derive_privkey_by_label(label)
    pub_key4 = priv_key4.get_pubkey()
    assert priv_key1.bn_key != priv_key4.bn_key
Example #8
0
class DelegatingPower(DerivedKeyBasedPower):

    def __init__(self,
                 keying_material: Optional[bytes] = None,
                 password: Optional[bytes] = None) -> None:
        if keying_material is None:
            self.__umbral_keying_material = UmbralKeyingMaterial()
        else:
            self.__umbral_keying_material = UmbralKeyingMaterial.from_bytes(key_bytes=keying_material,
                                                                            password=password)

    def _get_privkey_from_label(self, label):
        return self.__umbral_keying_material.derive_privkey_by_label(label)

    def get_pubkey_from_label(self, label):
        return self._get_privkey_from_label(label).get_pubkey()

    def generate_kfrags(self,
                        bob_pubkey_enc,
                        signer,
                        label: bytes,
                        m: int,
                        n: int
                        ) -> Tuple[UmbralPublicKey, List]:
        """
        Generates re-encryption key frags ("KFrags") and returns them.

        These KFrags can be used by Ursula to re-encrypt a Capsule for Bob so
        that he can activate the Capsule.
        :param bob_pubkey_enc: Bob's public key
        :param m: Minimum number of KFrags needed to rebuild ciphertext
        :param n: Total number of KFrags to generate
        """
        # TODO: salt?  #265

        __private_key = self._get_privkey_from_label(label)
        kfrags = pre.generate_kfrags(delegating_privkey=__private_key,
                                     receiving_pubkey=bob_pubkey_enc,
                                     threshold=m,
                                     N=n,
                                     signer=signer,
                                     sign_delegating_key=False,
                                     sign_receiving_key=False,
                                     )
        return __private_key.get_pubkey(), kfrags

    def get_decrypting_power_from_label(self, label):
        label_privkey = self._get_privkey_from_label(label)
        label_keypair = keypairs.DecryptingKeypair(private_key=label_privkey)
        decrypting_power = DecryptingPower(keypair=label_keypair)
        return decrypting_power
Example #9
0
class DelegatingPower(DerivedKeyBasedPower):

    def __init__(self):
        self.umbral_keying_material = UmbralKeyingMaterial()

    def generate_kfrags(self, bob_pubkey_enc, signer, label, m, n) -> Union[UmbralPublicKey, List]:
        """
        Generates re-encryption key frags ("KFrags") and returns them.

        These KFrags can be used by Ursula to re-encrypt a Capsule for Bob so
        that he can activate the Capsule.
        :param bob_pubkey_enc: Bob's public key
        :param m: Minimum number of KFrags needed to rebuild ciphertext
        :param n: Total number of rekey shares to generate
        """
        # TODO: salt?  #265

        __private_key = self.umbral_keying_material.derive_privkey_by_label(label)
        kfrags = pre.split_rekey(__private_key, signer, bob_pubkey_enc, m, n)
        return __private_key.get_pubkey(), kfrags
Example #10
0
    def generate(
        cls,
        passphrase: str,
        encrypting: bool = True,
        wallet: bool = True,
        tls: bool = True,
        host: str = None,
        curve: EllipticCurve = None,
        keyring_root: str = None,
    ) -> 'NucypherKeyring':
        """
        Generates new encrypting, signing, and wallet keys encrypted with the passphrase,
        respectively saving keyfiles on the local filesystem from *default* paths,
        returning the corresponding Keyring instance.
        """

        failures = cls.validate_passphrase(passphrase)
        if failures:
            raise cls.InvalidPassphrase(
                ", ".join(failures)
            )  # TODO: Ensure this scope is seperable from the scope containing the passphrase

        if not any((wallet, encrypting, tls)):
            raise ValueError(
                'Either "encrypting", "wallet", or "tls" must be True '
                'to generate new keys, or set "no_keys" to True to skip generation.'
            )

        _base_filepaths = cls._generate_base_filepaths(
            keyring_root=keyring_root)
        _public_key_dir = _base_filepaths['public_key_dir']
        _private_key_dir = _base_filepaths['private_key_dir']

        # Create the key directories with default paths. Raises OSError if dirs exist
        # if exists_ok and not os.path.isdir(_public_key_dir):
        os.mkdir(_public_key_dir, mode=0o744)  # public dir

        # if exists_ok and not os.path.isdir(_private_key_dir):
        os.mkdir(_private_key_dir, mode=0o700)  # private dir

        #
        # Generate New Keypairs
        #

        keyring_args = dict()

        if wallet is True:
            new_address, new_wallet = _generate_wallet(passphrase)
            new_wallet_path = os.path.join(
                _private_key_dir, 'wallet-{}.json'.format(new_address))
            saved_wallet_path = _write_private_keyfile(new_wallet_path,
                                                       json.dumps(new_wallet),
                                                       serializer=None)
            keyring_args.update(wallet_path=saved_wallet_path)
            account = new_address

        if encrypting is True:
            signing_private_key, signing_public_key = _generate_signing_keys()
            if not wallet:
                uncompressed_bytes = signing_public_key.to_bytes(
                    is_compressed=False)
                without_prefix = uncompressed_bytes[1:]
                verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix)
                account = verifying_key_as_eth_key.to_checksum_address()

        __key_filepaths = cls._generate_key_filepaths(
            account=account,
            private_key_dir=_private_key_dir,
            public_key_dir=_public_key_dir)
        if encrypting is True:
            encrypting_private_key, encrypting_public_key = _generate_encryption_keys(
            )
            delegating_keying_material = UmbralKeyingMaterial().to_bytes()

            # Derive Wrapping Keys
            passphrase_salt, encrypting_salt, signing_salt, delegating_salt = (
                os.urandom(32) for _ in range(4))
            derived_key_material = _derive_key_material_from_passphrase(
                salt=passphrase_salt, passphrase=passphrase)
            encrypting_wrap_key = _derive_wrapping_key_from_key_material(
                salt=encrypting_salt, key_material=derived_key_material)
            signature_wrap_key = _derive_wrapping_key_from_key_material(
                salt=signing_salt, key_material=derived_key_material)
            delegating_wrap_key = _derive_wrapping_key_from_key_material(
                salt=delegating_salt, key_material=derived_key_material)

            # TODO: Deprecate _encrypt_umbral_key with new pyumbral release
            # Encapsulate Private Keys
            encrypting_key_data = _encrypt_umbral_key(
                umbral_key=encrypting_private_key,
                wrapping_key=encrypting_wrap_key)
            signing_key_data = _encrypt_umbral_key(
                umbral_key=signing_private_key,
                wrapping_key=signature_wrap_key)
            delegating_key_data = bytes(
                SecretBox(delegating_wrap_key).encrypt(
                    delegating_keying_material))

            # Assemble Private Keys
            encrypting_key_metadata = _assemble_key_data(
                key_data=encrypting_key_data,
                master_salt=passphrase_salt,
                wrap_salt=encrypting_salt)
            signing_key_metadata = _assemble_key_data(
                key_data=signing_key_data,
                master_salt=passphrase_salt,
                wrap_salt=signing_salt)
            delegating_key_metadata = _assemble_key_data(
                key_data=delegating_key_data,
                master_salt=passphrase_salt,
                wrap_salt=delegating_salt)

            # Write Private Keys
            rootkey_path = _write_private_keyfile(
                keypath=__key_filepaths['root'],
                key_data=encrypting_key_metadata,
                serializer=cls._private_key_serializer)
            sigkey_path = _write_private_keyfile(
                keypath=__key_filepaths['signing'],
                key_data=signing_key_metadata,
                serializer=cls._private_key_serializer)
            delegating_key_path = _write_private_keyfile(
                keypath=__key_filepaths['delegating'],
                key_data=delegating_key_metadata,
                serializer=cls._private_key_serializer)

            # Write Public Keys
            root_keypath = _write_public_keyfile(
                __key_filepaths['root_pub'], encrypting_public_key.to_bytes())
            signing_keypath = _write_public_keyfile(
                __key_filepaths['signing_pub'], signing_public_key.to_bytes())

            # Commit
            keyring_args.update(
                keyring_root=keyring_root or cls.__default_keyring_root,
                root_key_path=rootkey_path,
                pub_root_key_path=root_keypath,
                signing_key_path=sigkey_path,
                pub_signing_key_path=signing_keypath,
                delegating_key_path=delegating_key_path,
            )

        if tls is True:
            if not all((host, curve)):
                raise ValueError(
                    "Host and curve are required to make a new keyring TLS certificate"
                )
            private_key, cert = _generate_tls_keys(host, curve)

            def __serialize_pem(pk):
                return pk.private_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PrivateFormat.TraditionalOpenSSL,
                    encryption_algorithm=serialization.BestAvailableEncryption(
                        password=derived_key_material))

            tls_key_path = _write_private_keyfile(
                keypath=__key_filepaths['tls'],
                key_data=__serialize_pem(pk=private_key),
                serializer=None)
            certificate_filepath = _write_tls_certificate(
                full_filepath=__key_filepaths['tls_certificate'],
                certificate=cert)
            keyring_args.update(tls_certificate_path=certificate_filepath,
                                tls_key_path=tls_key_path)

        keyring_instance = cls(account=account, **keyring_args)
        return keyring_instance
Example #11
0
 def __init__(self):
     self.umbral_keying_material = UmbralKeyingMaterial()
Example #12
0
    def generate(
        cls,
        password: str,
        encrypting: bool,
        wallet: bool,
        rest: bool,
        host: str = None,
        curve: EllipticCurve = None,
        keyring_root: str = None,
    ) -> 'NucypherKeyring':
        """
        Generates new encrypting, signing, and wallet keys encrypted with the password,
        respectively saving keyfiles on the local filesystem from *default* paths,
        returning the corresponding Keyring instance.
        """

        failures = cls.validate_password(password)
        if failures:
            raise cls.AuthenticationFailed(
                ", ".join(failures)
            )  # TODO: Ensure this scope is seperable from the scope containing the password

        if not any((wallet, encrypting, rest)):
            raise ValueError(
                'Either "encrypting", "wallet", or "tls" must be True '
                'to generate new keys, or set "no_keys" to True to skip generation.'
            )

        if curve is None:
            curve = cls.__DEFAULT_TLS_CURVE

        _base_filepaths = cls._generate_base_filepaths(
            keyring_root=keyring_root)
        _public_key_dir = _base_filepaths['public_key_dir']
        _private_key_dir = _base_filepaths['private_key_dir']

        # Write to disk
        os.mkdir(_public_key_dir, mode=0o744)  # public dir
        os.mkdir(_private_key_dir, mode=0o700)  # private dir

        #
        # Generate New Keypairs
        #

        keyring_args = dict()

        if wallet is True:
            new_address, new_wallet = _generate_wallet(password)
            new_wallet_path = os.path.join(
                _private_key_dir, 'wallet-{}.json'.format(new_address))
            with open(new_wallet_path,
                      'w') as wallet:  # TODO: is this pub or private?
                wallet.write(json.dumps(new_wallet))
            keyring_args.update(wallet_path=new_wallet_path)

        if encrypting is True:
            signing_private_key, signing_public_key = _generate_signing_keys()
            if not wallet:
                uncompressed_bytes = signing_public_key.to_bytes(
                    is_compressed=False)
                without_prefix = uncompressed_bytes[1:]
                verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix)
                new_address = verifying_key_as_eth_key.to_checksum_address()

        __key_filepaths = cls._generate_key_filepaths(
            account=new_address,
            private_key_dir=_private_key_dir,
            public_key_dir=_public_key_dir)
        if encrypting is True:
            encrypting_private_key, encrypting_public_key = _generate_encryption_keys(
            )
            delegating_keying_material = UmbralKeyingMaterial().to_bytes()

            # Derive Wrapping Keys
            password_salt, encrypting_salt, signing_salt, delegating_salt = (
                os.urandom(32) for _ in range(4))

            cls.log.info("About to derive key from password.")
            derived_key_material = derive_key_from_password(
                salt=password_salt, password=password.encode())
            encrypting_wrap_key = _derive_wrapping_key_from_key_material(
                salt=encrypting_salt, key_material=derived_key_material)
            signature_wrap_key = _derive_wrapping_key_from_key_material(
                salt=signing_salt, key_material=derived_key_material)
            delegating_wrap_key = _derive_wrapping_key_from_key_material(
                salt=delegating_salt, key_material=derived_key_material)

            # Encapsulate Private Keys
            encrypting_key_data = encrypting_private_key.to_bytes(
                wrapping_key=encrypting_wrap_key)
            signing_key_data = signing_private_key.to_bytes(
                wrapping_key=signature_wrap_key)
            delegating_key_data = bytes(
                SecretBox(delegating_wrap_key).encrypt(
                    delegating_keying_material))

            # Assemble Private Keys
            encrypting_key_metadata = _assemble_key_data(
                key_data=encrypting_key_data,
                master_salt=password_salt,
                wrap_salt=encrypting_salt)
            signing_key_metadata = _assemble_key_data(
                key_data=signing_key_data,
                master_salt=password_salt,
                wrap_salt=signing_salt)
            delegating_key_metadata = _assemble_key_data(
                key_data=delegating_key_data,
                master_salt=password_salt,
                wrap_salt=delegating_salt)

            # Write Private Keys
            rootkey_path = _write_private_keyfile(
                keypath=__key_filepaths['root'],
                key_data=encrypting_key_metadata,
                serializer=cls._private_key_serializer)
            sigkey_path = _write_private_keyfile(
                keypath=__key_filepaths['signing'],
                key_data=signing_key_metadata,
                serializer=cls._private_key_serializer)
            delegating_key_path = _write_private_keyfile(
                keypath=__key_filepaths['delegating'],
                key_data=delegating_key_metadata,
                serializer=cls._private_key_serializer)

            # Write Public Keys
            root_keypath = _write_public_keyfile(
                __key_filepaths['root_pub'], encrypting_public_key.to_bytes())
            signing_keypath = _write_public_keyfile(
                __key_filepaths['signing_pub'], signing_public_key.to_bytes())

            # Commit
            keyring_args.update(
                keyring_root=keyring_root or cls.__default_keyring_root,
                root_key_path=rootkey_path,
                pub_root_key_path=root_keypath,
                signing_key_path=sigkey_path,
                pub_signing_key_path=signing_keypath,
                delegating_key_path=delegating_key_path,
            )

        if rest is True:
            if not all(
                (host, curve, new_address)
            ):  # TODO: Do we want to allow showing up with an old wallet and generating a new cert?  Probably.
                raise ValueError(
                    "host, checksum_address and curve are required to make a new keyring TLS certificate. Got {}, {}"
                    .format(host, curve))
            private_key, cert = _generate_tls_keys(
                host=host, checksum_address=new_address, curve=curve)

            def __serialize_pem(pk):
                return pk.private_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PrivateFormat.TraditionalOpenSSL,
                    encryption_algorithm=serialization.BestAvailableEncryption(
                        password=derived_key_material))

            tls_key_path = _write_private_keyfile(
                keypath=__key_filepaths['tls'],
                key_data=__serialize_pem(pk=private_key),
                serializer=None)
            certificate_filepath = _write_tls_certificate(
                full_filepath=__key_filepaths['tls_certificate'],
                certificate=cert)
            keyring_args.update(tls_certificate_path=certificate_filepath,
                                tls_key_path=tls_key_path)

        keyring_instance = cls(account=new_address, **keyring_args)
        return keyring_instance
Example #13
0
    def generate(cls,
                 checksum_address: str,
                 password: str,
                 encrypting: bool = True,
                 rest: bool = False,
                 host: str = None,
                 curve: EllipticCurve = None,
                 keyring_root: str = None,
                 force: bool = False,
                 ) -> 'NucypherKeyring':
        """
        Generates new encrypting, signing, and wallet keys encrypted with the password,
        respectively saving keyfiles on the local filesystem from *default* paths,
        returning the corresponding Keyring instance.
        """

        keyring_root = keyring_root or cls._default_keyring_root

        failures = cls.validate_password(password)
        if failures:
            raise cls.AuthenticationFailed(", ".join(failures))  # TODO: Ensure this scope is seperable from the scope containing the password

        if not any((encrypting, rest)):
            raise ValueError('Either "encrypting", "wallet", or "tls" must be True '
                             'to generate new keys, or set "no_keys" to True to skip generation.')

        if curve is None:
            curve = cls.__DEFAULT_TLS_CURVE

        _base_filepaths = cls._generate_base_filepaths(keyring_root=keyring_root)
        _public_key_dir = _base_filepaths['public_key_dir']
        _private_key_dir = _base_filepaths['private_key_dir']

        #
        # Generate New Keypairs
        #

        keyring_args = dict()

        if checksum_address is not FEDERATED_ADDRESS:
            # Addresses read from some node keyrings (clients) are *not* returned in checksum format.
            checksum_address = to_checksum_address(checksum_address)

        if encrypting is True:
            signing_private_key, signing_public_key = _generate_signing_keys()

            if checksum_address is FEDERATED_ADDRESS:
                uncompressed_bytes = signing_public_key.to_bytes(is_compressed=False)
                without_prefix = uncompressed_bytes[1:]
                verifying_key_as_eth_key = EthKeyAPI.PublicKey(without_prefix)
                checksum_address = verifying_key_as_eth_key.to_checksum_address()

        else:
            # TODO: Consider a "Repair" mode here
            # signing_private_key, signing_public_key = ...
            pass

        if not checksum_address:
            raise ValueError("Checksum address must be provided for non-federated keyring generation")

        __key_filepaths = cls._generate_key_filepaths(account=checksum_address,
                                                      private_key_dir=_private_key_dir,
                                                      public_key_dir=_public_key_dir)
        if encrypting is True:
            encrypting_private_key, encrypting_public_key = _generate_encryption_keys()
            delegating_keying_material = UmbralKeyingMaterial().to_bytes()

            # Derive Wrapping Keys
            password_salt, encrypting_salt, signing_salt, delegating_salt = (os.urandom(32) for _ in range(4))

            cls.log.info("About to derive key from password.")
            derived_key_material = derive_key_from_password(salt=password_salt, password=password.encode())
            encrypting_wrap_key = _derive_wrapping_key_from_key_material(salt=encrypting_salt, key_material=derived_key_material)
            signature_wrap_key = _derive_wrapping_key_from_key_material(salt=signing_salt, key_material=derived_key_material)
            delegating_wrap_key = _derive_wrapping_key_from_key_material(salt=delegating_salt, key_material=derived_key_material)

            # Encapsulate Private Keys
            encrypting_key_data = encrypting_private_key.to_bytes(wrapping_key=encrypting_wrap_key)
            signing_key_data = signing_private_key.to_bytes(wrapping_key=signature_wrap_key)
            delegating_key_data = bytes(SecretBox(delegating_wrap_key).encrypt(delegating_keying_material))

            # Assemble Private Keys
            encrypting_key_metadata = _assemble_key_data(key_data=encrypting_key_data,
                                                         master_salt=password_salt,
                                                         wrap_salt=encrypting_salt)
            signing_key_metadata = _assemble_key_data(key_data=signing_key_data,
                                                      master_salt=password_salt,
                                                      wrap_salt=signing_salt)
            delegating_key_metadata = _assemble_key_data(key_data=delegating_key_data,
                                                         master_salt=password_salt,
                                                         wrap_salt=delegating_salt)

            #
            # Write Keys
            #

            # Create base paths if the do not exist.
            os.makedirs(abspath(keyring_root), exist_ok=True, mode=0o700)
            if not os.path.isdir(_public_key_dir):
                os.mkdir(_public_key_dir, mode=0o744)  # public dir
            if not os.path.isdir(_private_key_dir):
                os.mkdir(_private_key_dir, mode=0o700)  # private dir

            try:
                rootkey_path = _write_private_keyfile(keypath=__key_filepaths['root'],
                                                      key_data=encrypting_key_metadata,
                                                      serializer=cls._private_key_serializer)

                sigkey_path = _write_private_keyfile(keypath=__key_filepaths['signing'],
                                                     key_data=signing_key_metadata,
                                                     serializer=cls._private_key_serializer)

                delegating_key_path = _write_private_keyfile(keypath=__key_filepaths['delegating'],
                                                             key_data=delegating_key_metadata,
                                                             serializer=cls._private_key_serializer)

                # Write Public Keys
                root_keypath = _write_public_keyfile(__key_filepaths['root_pub'], encrypting_public_key.to_bytes())
                signing_keypath = _write_public_keyfile(__key_filepaths['signing_pub'], signing_public_key.to_bytes())
            except (PrivateKeyExistsError, FileExistsError):
                if not force:
                    raise ExistingKeyringError(f"There is an existing keyring for address '{checksum_address}'")
            else:
                # Commit
                keyring_args.update(
                    keyring_root=keyring_root,
                    root_key_path=rootkey_path,
                    pub_root_key_path=root_keypath,
                    signing_key_path=sigkey_path,
                    pub_signing_key_path=signing_keypath,
                    delegating_key_path=delegating_key_path,
                )

        if rest is True:
            if not all((host, curve, checksum_address)):  # TODO: Do we want to allow showing up with an old wallet and generating a new cert?  Probably.
                raise ValueError("host, checksum_address and curve are required to make a new keyring TLS certificate. Got {}, {}".format(host, curve))
            private_key, cert = _generate_tls_keys(host=host, checksum_address=checksum_address, curve=curve)

            def __serialize_pem(pk):
                return pk.private_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PrivateFormat.TraditionalOpenSSL,
                    encryption_algorithm=serialization.BestAvailableEncryption(password=derived_key_material)
                )

            tls_key_path = _write_private_keyfile(keypath=__key_filepaths['tls'], key_data=__serialize_pem(pk=private_key), serializer=None)
            certificate_filepath = _write_tls_certificate(full_filepath=__key_filepaths['tls_certificate'], certificate=cert)
            keyring_args.update(tls_certificate_path=certificate_filepath, tls_key_path=tls_key_path)

        keyring_instance = cls(account=checksum_address, **keyring_args)
        return keyring_instance