16

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()
    )

2 Answers 2

31

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)
Sign up to request clarification or add additional context in comments.

2 Comments

How to load key as string? not <cryptography.hazmat.backends.openssl.rsa._RSAPublicKey object at 0x10be06220>
@reza_khalafi: If the string is in a supported format you just pass the string to load_pem_private_key in place of pemlines. See the documentation for information on supported formats.
3
import rsa

if __name__ == '__main__':

  (pubkey, privkey) = rsa.newkeys(512, poolsize=4)

  message = b'Say hi!'
  crypto = rsa.encrypt(message, pubkey)

  PRIV_KEY_DST = 'your path to file'
  with open(PRIV_KEY_DST, 'wb+') as f:
    pk = rsa.PrivateKey.save_pkcs1(privkey, format='PEM')
    f.write(pk)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.