pythoncryptographyrsa

Python Cryptography module save/load RSA keys to/from file


Using the Cryptography module for Python,

I want to save my generated private key in a file, to use it later on.

But from the docs I was unable to find the method needed for this.

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

# Working RSA encryption you can run for yourself
MESSAGE = 'I am a very secret message'

# Create private key
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
    backend=default_backend()
)

# Create public key
public_key = private_key.public_key()

# Encrypt
ciphertext = public_key.encrypt(
    MESSAGE,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA1()),
        algorithm=hashes.SHA1(),
        label=None
    )
)

# Encrypted text
print ciphertext

# Decrypt
plaintext = private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA1()),
        algorithm=hashes.SHA1(),
        label=None
    )
)

# Decrypted text
print plaintext

# Print human readable key
pem = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.TraditionalOpenSSL,
    encryption_algorithm=serialization.NoEncryption()
)
pem_data = pem.splitlines()
print pem_data


# How to Save//Load

I know how to generate keys, but how can I save correctly to a file. By just storing the pem_data in a file and later on loading from that file with load_pem_public_key?

Since Cryptography is still new for me, I would like to know the correct way of storing RSA keys in a file.

This is my current try, but I get an error.

ValueError: Could not deserialize key data.

if os.path.exists('key.pem'):
    print 'file exist'
else:
    f = open(os.path.join(__location__, 'key.pem'), 'w')
    for i in pem_data:
       f.write(i)
    f.close()

with open(os.path.join(__location__, 'key.pem'), "rb") as key_file:
   private_key = serialization.load_pem_private_key(
        key_file.read(),
        password=None,
        backend=default_backend()
    )

Solution

  • Your method of saving the private key throws away the newlines which load_pem_private_key() expects to see. I have modified your example slightly to illustrate this. The method save_key_bad() is your method, and the method save_key() shows a simple correct method.

    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.primitives.asymmetric import rsa
    from cryptography.hazmat.primitives import serialization
    from cryptography.hazmat.primitives.serialization import load_pem_private_key
    
    
    def gen_key():
        private_key = rsa.generate_private_key(
            public_exponent=65537, key_size=2048, backend=default_backend()
        )
        return private_key
    
    
    def save_key(pk, filename):
        pem = pk.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption()
        )
        with open(filename, 'wb') as pem_out:
            pem_out.write(pem)
    
    
    def save_key_bad(pk, filename):
        pem = pk.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption()
        )
        pem_data = pem.splitlines()
        with open(filename, 'wb') as pem_out:
            for line in pem_data:
                pem_out.write(line)
    
    
    def load_key(filename):
        with open(filename, 'rb') as pem_in:
            pemlines = pem_in.read()
        private_key = load_pem_private_key(pemlines, None, default_backend())
        return private_key
    
    
    if __name__ == '__main__':
        pk = gen_key()
        filename = 'privkey.pem'
        save_key(pk, filename)
        pk2 = load_key(filename)
        save_key_bad(pk, filename)
        pk3 = load_key(filename)