Ejemplo n.º 1
0
 def __init__(self, username: str, wallet_dir: str,
              k_sk_receiver: PrivateKey):
     self.username = username
     self.wallet_dir = wallet_dir
     self.k_sk_receiver = k_sk_receiver
     self.k_sk_receiver_bytes = \
         k_sk_receiver.encode(encoder=encoding.RawEncoder)
Ejemplo n.º 2
0
class IDPrivateKey:
    
    def __init__(self, password = None, email = None):
        if email is None:
            self.salt = defaultsalt
        else:
            self.salt = email
        if password is not None:
            self.generate_key(password)

    def generate_key(self, password):
        self.pri = PrivateKey(scrypt(sha512(password,encoder = RawEncoder),
                                     self.salt,
                                     N = 1<<17,
                                     r = 8,
                                     p = 1,
                                     buflen = 32),
                              encoder = RawEncoder)
        pub = PublicID()
        pub.salt = self.salt
        pub.key = self.pri.public_key.encode()
        self.pub = pub

    def to_private_key(self):
        return self.pri

    def to_public_key(self):
        return self.pub

    def pri_base58(self):
        return b58encode(self.pri.encode(encoder = RawEncoder))

    def pub_base58(self):
        return self.pub.base58()
Ejemplo n.º 3
0
class Crypto:
	
	def __init__(self):
		"""
		Initialize crypto stuff
		"""
		
		try:
			with open("SecretKey", "rb") as SecKeyFile:
				key = SecKeyFile.read()
		except Exception:
			logging.info("No secret key yet -> Generate new one")
			key = None
		
		if key:
			self.secKey = PrivateKey(key, nacl.encoding.HexEncoder)
			self.pubKey = self.secKey.public_key
		else:
			self.secKey = PrivateKey.generate()
			self.pubKey = self.secKey.public_key
		
		self.secKey_string = self.secKey.encode(nacl.encoding.HexEncoder).upper()
		self.pubKey_string = self.pubKey.encode(nacl.encoding.HexEncoder).upper()
		
		try:
			with open("SecretKey", "wb") as SecKeyFile, open("PublicKey", "wb") as PubKeyFile:
				SecKeyFile.write(self.secKey_string)
				PubKeyFile.write(self.pubKey_string)
		except Exception:
			logging.exception("Could not save secret key!")
			sys.exit(1)
	
	@staticmethod
	def compute_checksum(pk, nospam):
		"""
		Return the checksum for the public key + NoSpam value
		"""
		checksum = [0, 0] # initializing
		
		for number, byte in enumerate(nacl.encoding.HexEncoder.decode(pk + nospam)):
			checksum[number % 2] ^= byte
		return "".join(hex(byte)[2:].zfill(2) for byte in checksum).upper()
	
	@staticmethod
	def decrypt_request(secKey, pubKey_client, ciphertext, nonce):
		"""
		Decrypt the ciphertext and return plaintext
		"""
		box = Box(secKey, pubKey_client)
		plain = box.decrypt(ciphertext, nonce)
		
		return plain
Ejemplo n.º 4
0
class XMMPPSex():
	def __init__(self, jid):
		self.jid = jid
		self.pk = {}
		if os.path.isfile(SECKEY_FILE.format(jid=jid)):
			print("Reading secret key for {} from file.".format(jid))
			with open(SECKEY_FILE.format(jid=jid), 'rb') as f:
				self.sk = PrivateKey(nacl.encoding.URLSafeBase64Encoder.decode(f.read()))
		else:
			print("Generating new secret key for {} and writing it to file.".format(jid))
			self.sk = PrivateKey.generate()
			with open(SECKEY_FILE.format(jid=jid), 'wb') as f:
				f.write(self.sk.encode(encoder=nacl.encoding.URLSafeBase64Encoder))

		if not os.path.isfile(PUBKEY_FILE.format(jid=jid)):
			print("Writing public key for {} to file.".format(jid))
			with open(PUBKEY_FILE.format(jid=jid), 'wb') as f:
				f.write(self.sk.public_key.encode(encoder=nacl.encoding.URLSafeBase64Encoder))

	def addPubkey(self, jid):
		print("Adding public key for {} from file.".format(jid))
		with open(PUBKEY_FILE.format(jid=jid), 'rb') as f:
			self.pk[jid] = PublicKey(nacl.encoding.URLSafeBase64Encoder.decode(f.read()))

	def encryptTo(self, jid, message):
		if not jid in self.pk:
			self.addPubkey(jid)
		box = Box(self.sk, self.pk[jid])
		nonce = nacl.utils.random(Box.NONCE_SIZE)
		return (nacl.encoding.URLSafeBase64Encoder.encode(nonce).decode('utf-8'),
			box.encrypt(message.encode('utf-8'), nonce, nacl.encoding.URLSafeBase64Encoder).ciphertext.decode('utf-8'))

	def decryptFrom(self, jid, message, nonce):
		if not jid in self.pk:
			self.addPubkey(jid)
		box = Box(self.sk, self.pk[jid])
		return box.decrypt(message,
			nacl.encoding.URLSafeBase64Encoder.decode(nonce),
			nacl.encoding.URLSafeBase64Encoder).decode('utf-8')
Ejemplo n.º 5
0
#PKs2_full = loads('{"kty":"EC", "crv":"Curve25519", "x":""}', object_pairs_hook=OrderedDict)
#PKp2_full = loads('{"kty":"EC", "crv":"Curve25519", "x":""}', object_pairs_hook=OrderedDict)

PKp_full['x'] = PKp_b64
PKs_full['x'] = PKs_b64
#PKs2_full['x'] = PKs2_b64
#PKp2_full['x'] = PKp2_b64

## Load peer and server private keys
SK_peer = PrivateKey(bytes.fromhex(SKp))
SK_server = PrivateKey(bytes.fromhex(SKs))
#SK2_peer = PrivateKey(bytes.fromhex(SKp2))
#SK2_server = PrivateKey(bytes.fromhex(SKs2))

## Derive shared secret
Z = scalarmult(SK_peer.encode(), PK_server.encode())
assert (Z == scalarmult(SK_server.encode(), PK_peer.encode()))
#Z2 = scalarmult(SK2_peer.encode(), PK2_server.encode())
#assert(Z2 == scalarmult(SK2_server.encode(), PK2_peer.encode()))

## KDF for completion exchange. Uses NIST Concat KDF.
KDF_input = b'EAP-NOOB' + base64url_decode(Np_b64) + base64url_decode(
    Ns_b64) + base64url_decode(Noob_b64)
KDF_out = KDF(algorithm=SHA256(),
              length=320,
              otherinfo=KDF_input,
              backend=default_backend()).derive(Z)
Kms = KDF_out[224:256]
Kmp = KDF_out[256:288]
Kz = KDF_out[288:320]
Ejemplo n.º 6
0
class PrivateKeyProvider(object):
    """
    Decrypts private keys.
    """

    def __init__(self, key, passphrase: bytes):
        self.key = key
        # Secure!
        self.passphrase = passphrase

        self.sign = None
        self.encrypt = None

    def __enter__(self) -> typing.Tuple[PrivateKey, PrivateKey]:
        """
        Provides a pair of private keys.
        """
        # Derive the key from the passphrase.
        derived = util.derive_passphrase(self.passphrase)

        sign_box = SecretBox(derived)
        enc_box = SecretBox(derived)

        # Decrypt, using the two nonces.
        s_d = sign_box.decrypt(self.key._private_signing_seed, self.key._private_signing_nonce)
        e_d = enc_box.decrypt(self.key._private_key_raw, self.key._private_nonce)

        # Generate a SigningKey out of the seed.
        self.sign = SigningKey(s_d)
        self.encrypt = PrivateKey(e_d)

        # Update the key's public keys.
        if self.key._public_key is None:
            self.key._public_key = self.encrypt.public_key

        if self.key._public_signing_key is None:
            self.key._public_signing_key = self.sign.verify_key

        return self.encrypt, self.sign

    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        Re-encrypt.
        """
        # Derive the key from the passphrase.
        derived = util.derive_passphrase(self.passphrase)

        # Generate two random nonces.
        nonce1 = random(SecretBox.NONCE_SIZE)
        nonce2 = random(SecretBox.NONCE_SIZE)

        sign_box = SecretBox(derived)
        enc_box = SecretBox(derived)

        s_p = self.sign.encode()
        e_p = self.encrypt.encode()

        s_e = sign_box.encrypt(s_p, nonce1)
        e_e = enc_box.encrypt(e_p, nonce2)

        # Update `self.key`.
        self.key._private_key_raw = e_e.ciphertext
        self.key._private_signing_key_raw = s_e.ciphertext

        # Bit of a mixed up name.
        self.key._private_nonce = e_e.nonce
        self.key._private_signing_nonce = s_e.nonce

        if exc_type is not None:
            raise exc_type(exc_val)
Ejemplo n.º 7
0
 def _serialize_private_key(key: public.PrivateKey) -> str:
     str_key = key.encode(encoder=nacl.encoding.HexEncoder).decode('ascii')
     return str_key
Ejemplo n.º 8
0
# PKp2_full = loads('{"kty":"EC", "crv":"Curve25519", "x":""}', \
#     object_pairs_hook=OrderedDict)

PKp_full['x'] = PKp_b64
PKs_full['x'] = PKs_b64
#PKs2_full['x'] = PKs2_b64
#PKp2_full['x'] = PKp2_b64

## Load peer and server private keys
SK_peer = PrivateKey(bytes.fromhex(SKp))
SK_server = PrivateKey(bytes.fromhex(SKs))
#SK2_peer = PrivateKey(bytes.fromhex(SKp2))
#SK2_server = PrivateKey(bytes.fromhex(SKs2))

## Derive shared secret
Z = scalarmult(SK_peer.encode(), PK_server.encode())
assert(Z == scalarmult(SK_server.encode(), PK_peer.encode()))
#Z2 = scalarmult(SK2_peer.encode(), PK2_server.encode())
#assert(Z2 == scalarmult(SK2_server.encode(), PK2_peer.encode()))

## KDF for completion exchange. Uses NIST Concat KDF.
KDF_input = b'EAP-NOOB' + base64url_decode(Np_b64) + base64url_decode(Ns_b64) +\
    base64url_decode(Noob_b64)
KDF_out = KDF(algorithm=SHA256(), length=320, otherinfo=KDF_input,
    backend=default_backend()).derive(Z)
Kms = KDF_out[224:256]
Kmp = KDF_out[256:288]
Kz = KDF_out[288:320]

# KDF - for reconnect exchange. Uses NIST Concat KDF. This sample script does
# not exchange new keys in the reconnect exchange and uses the Kz from the
Ejemplo n.º 9
0
class HTTPMailboxServer(BaseServer):
    """I am a local HTTP-based server, attached to our webapi port. I don't
    persist anything myself, but expect my creator to provide me with our
    persistent state. I can deliver messages to a local transport (endpoints
    inside our same process), or write messages to disk for later retrieval
    by remote clients.
    """
    def __init__(self, web, enable_retrieval, desc):
        BaseServer.__init__(self)
        self.web = web
        self.privkey = PrivateKey(desc["transport_privkey"].decode("hex"))
        self.TID_privkey = desc["TID_private_key"].decode("hex")

        # If we feed a local transport, it will have just one TID. If we
        # queue messages for any other transports, they'll each have their
        # own TID and handler (e.g. a queue and some retrieval credentials).
        self.local_TID0 = desc["local_TID0"].decode("hex")
        self.local_TID_tokenid = desc["local_TID_tokenid"].decode("hex")

        # this is how we get messages from senders
        web.get_root().putChild("mailbox", ServerResource(self.handle_msgA))

        if enable_retrieval:
            # add a second resource for clients to retrieve messages
            raise NotImplementedError()

    def get_retrieval_descriptor(self):
        return {
            "type": "local",
            "transport_privkey": self.privkey.encode().encode("hex"),
            "TID_private_key": self.TID_privkey.encode("hex"),
            "TID": self.local_TID0.encode("hex"),
            "TID_tokenid": self.local_TID_tokenid.encode("hex"),
        }

    def get_sender_descriptor(self):
        baseurl = self.web.get_baseurl()
        assert baseurl.endswith("/")
        pubkey = self.privkey.public_key
        return {
            "type": "http",
            # TODO: we must learn our local ipaddr and the webport
            "url": baseurl + "mailbox",
            "transport_pubkey": pubkey.encode().encode("hex"),
        }

    def register_local_transport_handler(self, handler):
        self.local_transport_handler = handler

    def handle_msgA(self, msgA):
        pubkey1_s, boxed = parseMsgA(msgA)
        msgB = Box(self.privkey, PublicKey(pubkey1_s)).decrypt(boxed)
        # this ends the observable errors
        eventually(self.handle_msgB, msgB)

    def handle_msgB(self, msgB):
        MSTID, msgC = parseMsgB(msgB)
        TID = rrid.decrypt(self.TID_privkey, MSTID)
        if TID == self.local_TID_tokenid:
            self.local_transport_handler(msgC)
        else:
            # TODO: look up registered transports, queue message
            self.signal_unrecognized_TID(TID)

    def signal_unrecognized_TID(self, TID):
        # this can be overridden by unit tests
        raise KeyError("unrecognized transport identifier")
def nacl_public_PrivateKey():
    key1 = PrivateKey(random(size=PrivateKey.SIZE))  # 32
    print(key1.encode())

    key2 = PrivateKey.generate()
    print(key2.encode())
Ejemplo n.º 11
0
            "result"] else []

context = zmq.Context()
tag = 1
for s in states:
    pk = s["service_node_pubkey"]
    if pk in missed:
        missed.remove(pk)
    if "_connect" not in s:
        ip, port = s["public_ip"], s["quorumnet_port"]
        if not ip or not port:
            print("SN {} has no IP/qnet port: {}:{}".format(pk, ip, port))
    else:
        ip, port = None, None
    socket = context.socket(zmq.DEALER)
    socket.curve_secretkey = x_key.encode()
    socket.curve_publickey = x_key.public_key.encode()
    socket.curve_serverkey = bytes.fromhex(s["pubkey_x25519"])
    socket.setsockopt(zmq.CONNECT_TIMEOUT, 5000)
    socket.setsockopt(zmq.HANDSHAKE_IVL, 5000)
    socket.setsockopt(zmq.IMMEDIATE, 1)
    if "_connect" in s:
        socket.connect(s["_connect"])
        print("Ping {} (for SN {})".format(s["_connect"], pk))
    else:
        socket.connect("tcp://{}:{}".format(ip, port))
        print("Ping {}:{} (for SN {})".format(ip, port, pk))

    bt_tag = bytes("i{}e".format(tag), "utf-8")
    socket.send_multipart((b"ping.ping", b"d1:!" + bt_tag + b"e"))
    ponged = False
Ejemplo n.º 12
0
    assert STORAGE_PIR_DIR[-1] == '/'
    assert HTTP_STATIC_DIR[-1] == '/'
    assert Box.NONCE_SIZE == NONCE_BYTES

    commandlineoptions = parse_options()

    keyfile = 'server.secret'

    if os.path.exists(keyfile):
        with open(keyfile, 'rb') as f:
            data = f.read()
            sk_bin = data[0:32]
            server_sk = PrivateKey(sk_bin)
    else:
        server_sk = PrivateKey.generate()
        sk_bin = server_sk.encode(encoder=nacl.encoding.RawEncoder)

        with open(keyfile, 'wb') as f:
            f.write(sk_bin)

    pk_bin = server_sk.public_key.encode(encoder=nacl.encoding.RawEncoder)
    print "Server public key: " + pk_bin.encode('hex')

    HOST, PORT = "0.0.0.0", commandlineoptions.port

    # Update the PIR manifest
    update_pir_manifest()

    # Create the server
    print "[INFO] Starting server at", str(HOST) + ":" + str(PORT)
    onionpir_server = SocketServer.TCPServer((HOST, PORT), NonPirTCPHandler)
Ejemplo n.º 13
0
class HTTPMailboxServer(BaseServer):
    """I am a local HTTP-based server, attached to our webapi port. I don't
    persist anything myself, but expect my creator to provide me with our
    persistent state. I can deliver messages to a local transport (endpoints
    inside our same process), or write messages to disk for later retrieval
    by remote clients.
    """

    def __init__(self, web, enable_retrieval, desc):
        BaseServer.__init__(self)
        self.web = web
        self.privkey = PrivateKey(desc["transport_privkey"].decode("hex"))
        self.TID_privkey = desc["TID_private_key"].decode("hex")

        # If we feed a local transport, it will have just one TID. If we
        # queue messages for any other transports, they'll each have their
        # own TID and handler (e.g. a queue and some retrieval credentials).
        self.local_TID0 = desc["local_TID0"].decode("hex")
        self.local_TID_tokenid = desc["local_TID_tokenid"].decode("hex")

        # this is how we get messages from senders
        web.get_root().putChild("mailbox", ServerResource(self.handle_msgA))

        if enable_retrieval:
            # add a second resource for clients to retrieve messages
            raise NotImplementedError()

    def get_retrieval_descriptor(self):
        return { "type": "local",
                 "transport_privkey": self.privkey.encode().encode("hex"),
                 "TID_private_key": self.TID_privkey.encode("hex"),
                 "TID": self.local_TID0.encode("hex"),
                 "TID_tokenid": self.local_TID_tokenid.encode("hex"),
                 }

    def get_sender_descriptor(self):
        baseurl = self.web.get_baseurl()
        assert baseurl.endswith("/")
        pubkey = self.privkey.public_key
        return { "type": "http",
                 # TODO: we must learn our local ipaddr and the webport
                 "url": baseurl + "mailbox",
                 "transport_pubkey": pubkey.encode().encode("hex"),
                 }

    def register_local_transport_handler(self, handler):
        self.local_transport_handler = handler

    def handle_msgA(self, msgA):
        pubkey1_s, boxed = parseMsgA(msgA)
        msgB = Box(self.privkey, PublicKey(pubkey1_s)).decrypt(boxed)
        # this ends the observable errors
        eventually(self.handle_msgB, msgB)

    def handle_msgB(self, msgB):
        MSTID, msgC = parseMsgB(msgB)
        TID = rrid.decrypt(self.TID_privkey, MSTID)
        if TID == self.local_TID_tokenid:
            self.local_transport_handler(msgC)
        else:
            # TODO: look up registered transports, queue message
            self.signal_unrecognized_TID(TID)

    def signal_unrecognized_TID(self, TID):
        # this can be overridden by unit tests
        raise KeyError("unrecognized transport identifier")
Ejemplo n.º 14
0
class Keyring:

    keyring = ''  # versioned keyring name (ex. 'cats/0')

    # for asymmetric encryption
    enc_key = None
    enc_key_id = None

    # for signing
    signing_key = None
    signing_key_id = None

    # for symmetric encryption
    _master_key = None
    _secret_box = None

    def __init__(self, user, keyring, filename=None):
        """
        we want to keep all the cryptographic functions as side-effect
        free as possible, so when we instantiate a keyring we'll do as
        much of the setup and I/O as possible.
        """
        self.keyring = keyring
        if not filename:
            filename = keyring.lstrip('/key').replace('/', '.')
            filename = os.path.join(DIR, '{}.{}'.format(user, filename))

        try:
            self._load_from_private_keyfile(filename)
        except FileNotFoundError:
            self.enc_key = PrivateKey.generate()
            self.signing_key = nacl.signing.SigningKey.generate()
            self.enc_key_id = uuid.uuid4().hex
            self.signing_key_id = uuid.uuid4().hex
            self._to_private_keyfile(filename)

    def generate_master_key(self):
        """
        create a new master key. the user will want to write this master
        key to the PDI by vouching for themselves and then vouch for any
        other users who want to use the same key.
        """
        self._master_key = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE)
        self._secret_box = nacl.secret.SecretBox(self._master_key)

    def vouch(self, public_key):
        """
        given the public key of another user, asymmetrically encrypt the
        master key. this encryption inherently includes authentication so
        we don't need to also sign this block.
        """
        assert self._master_key is not None
        pkey = PublicKey(public_key, encoder=nacl.encoding.HexEncoder)
        box = Box(self.enc_key, pkey)
        encrypted = box.encrypt(self._master_key)
        data = {'version': VERSION, 'key': encrypted.hex()}
        return json.dumps(data).encode('ascii')

    def load_master_key(self, block, public_key):
        """
        given a master key block from the PDI encrypted for this user,
        and the public key of the user that vouched for them, load the
        master key into memory and set up the symmetric encryption engine.
        Note that we can't do this in the constructor because only the
        first keyring user is going to want to generate a new master key.
        (Note: this is the reverse operation to 'vouch')
        """
        pkey = PublicKey(public_key, encoder=nacl.encoding.HexEncoder)
        block = json.loads(block.decode('ascii'))['key']
        msg = nacl.utils.EncryptedMessage.fromhex(block)
        box = Box(self.enc_key, pkey)
        plaintext = box.decrypt(msg)
        self._master_key = plaintext
        self._secret_box = nacl.secret.SecretBox(self._master_key)

    def encrypt(self, plaintext):
        """
        symmetric encryption of the message body using the master
        key. asserts that we've loaded the master key onto the keyring
        """
        assert self._master_key is not None
        assert self._secret_box is not None
        ciphertext = self._secret_box.encrypt(plaintext)
        return ciphertext

    def decrypt(self, ciphertext):
        """
        symmetric decryption of the message body using the master
        key. asserts that we've loaded the master key onto the keyring
        """
        assert self._master_key is not None
        assert self._secret_box is not None
        plaintext = self._secret_box.decrypt(ciphertext)
        return plaintext

    def sign(self, data):
        """
        given a blob of data, add a message signature
        """
        signed = self.signing_key.sign(data)
        return signed

    def verify(self, block, verify_key_hex):
        """
        given a data block (which should be encrypted) and the encoded
        signing verify key of a user, verify the message signature.
        will raise nacl.exceptions.BadSignatureError if the check fails
        """
        verify_key = nacl.signing.VerifyKey(verify_key_hex,
                                            encoder=nacl.encoding.HexEncoder)
        message = verify_key.verify(block)
        return message

    @property
    def public_key(self):
        return self.enc_key.public_key.encode(JSONSafeHexEncoder())

    def to_public_keyblock(self):
        """
        output the JSON representation of the asymmetric public key
        for writing to the PDI key keyring
        """
        data = {
            'version': VERSION,
            'key': {
                'crv': CURVE,
                'kty': KEY_TYPE,
                'kid': self.enc_key_id,
                'use': 'enc',
                'x': self.enc_key.public_key.encode(JSONSafeHexEncoder())
            }
        }
        return json.dumps(data).encode('ascii')

    @property
    def verify_key(self):
        return self.signing_key.verify_key.encode(JSONSafeHexEncoder())

    def to_verify_keyblock(self):
        """
        output the JSON representation of the signing verify key
        for writing to the PDI key keyring
        """
        data = {
            'version': VERSION,
            'key': {
                'crv': CURVE,
                'kty': KEY_TYPE,
                'kid': self.signing_key_id,
                'use': 'signing',
                'x': self.signing_key.verify_key.encode(JSONSafeHexEncoder())
            }
        }
        return json.dumps(data).encode('ascii')

    def _load_from_private_keyfile(self, filename):
        """
        loads the user's private keys from a local file into memory.
        in a real SKI this will use the secure persistent implementation
        of the SKI's hardware backing
        """
        try:
            with open(filename, 'r') as keyfile:
                data = json.loads(keyfile.read())
                for key in data['keys']:
                    if key['use'] == 'signing':
                        hex_key = key['x']
                        self.signing_key_id = key['kid']
                        self.signing_key = nacl.signing.SigningKey(
                            hex_key, nacl.encoding.HexEncoder())
                    elif key['use'] == 'enc':
                        hex_key = key['x']
                        self.enc_key_id = key['kid']
                        self.enc_key = PrivateKey(hex_key,
                                                  nacl.encoding.HexEncoder())

        except PermissionError:
            # a keyfile exists but we're not allowed to get it.
            print('tried to access keyfile {} but got PermissionError'.format(
                filename))
            sys.exit(77)
        except (KeyError, json.decoder.JSONDecodeError):
            print('private keyfile {} was in invalid format'.format(filename))
            sys.exit(1)
        except FileNotFoundError:
            # let this bubble up so that we can create a new keyfile
            raise

    def _to_private_keyfile(self, filename):
        """
        write the user's private keys to local file. in a real SKI
        this will have a secure persistence implementation taking
        advantage of the SKI's hardware backing
        """
        data = {
            'version':
            VERSION,
            'keys': [{
                'crv': CURVE,
                'kty': KEY_TYPE,
                'kid': self.signing_key_id,
                'use': 'signing',
                'x': self.signing_key.encode(JSONSafeHexEncoder())
            }, {
                'crv': CURVE,
                'kty': KEY_TYPE,
                'kid': self.enc_key_id,
                'use': 'enc',
                'x': self.enc_key.encode(JSONSafeHexEncoder())
            }]
        }
        try:
            with open(filename, 'w') as keyfile:
                keyfile.write(json.dumps(data))
        except Exception:
            raise  # just crash at this point so we can debug this