Files
PGPy-3_13_patch/docs/source/examples/keys.rst
2017-04-13 14:46:21 -07:00

151 lines
5.9 KiB
ReStructuredText

Keys
====
Generating Keys
---------------
PGPy can generate most types keys as defined in the standard.
Generating Primary Keys
^^^^^^^^^^^^^^^^^^^^^^^
It is possible to generate most types of keys with PGPy now. The process is mostly straightforward::
from pgpy.constants import PubKeyAlgorithm, KeyFlags, HashAlgorithm, SymmetricKeyAlgorithm, CompressionAlgorithm
# we can start by generating a primary key. For this example, we'll use RSA, but it could be DSA or ECDSA as well
key = pgpy.PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096)
# we now have some key material, but our new key doesn't have a user ID yet, and therefore is not yet usable!
uid = pgpy.PGPUID.new('Abraham Lincoln', comment='Honest Abe', email='abraham.lincoln@whitehouse.gov')
# now we must add the new user id to the key. We'll need to specify all of our preferences at this point
# because PGPy doesn't have any built-in key preference defaults at this time
# this example is similar to GnuPG 2.1.x defaults, with no expiration or preferred keyserver
key.add_uid(uid, usage={KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage},
hashes=[HashAlgorithm.SHA256, HashAlgorithm.SHA384, HashAlgorithm.SHA512, HashAlgorithm.SHA224],
ciphers=[SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.AES192, SymmetricKeyAlgorithm.AES128],
compression=[CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZ2, CompressionAlgorithm.ZIP, CompressionAlgorithm.Uncompressed])
Specifying key expiration can be done using the ``key_expires`` keyword when adding the user id. Expiration can be specified
using a :py:obj:`datetime.datetime` or a :py:obj:`datetime.timedelta` object::
from datetime import timedelta
# in this example, we'll use fewer preferences for the sake of brevity, and set the key to expire in 10 years
key = pgpy.PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096)
uid = pgpy.PGPUID.new('Nikola Tesla') # comment and email are optional
# the key_expires keyword accepts a :py:obj:`datetime.datetime`
key.add_uid(uid, usage={KeyFlags.Sign}, hashes=[HashAlgorithm.SHA512, HashAlgorithm.SHA256],
ciphers=[SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.Camellia256],
compression=[CompressionAlgorithm.BZ2, CompressionAlgorithm.Uncompressed],
key_expires=timedelta(days=365))
Generating Sub Keys
^^^^^^^^^^^^^^^^^^^
Generating a subkey is similar to the process above, except that it requires an existing primary key::
# assuming we already have a primary key, we can generate a new key and add it as a subkey thusly:
subkey = pgpy.PGPKey.new(PubKeyAlgorithm.RSA, 4096)
# preferences that are specific to the subkey can be chosen here
# any preference(s) needed for actions by this subkey that not specified here
# will seamlessly "inherit" from those specified on the selected User ID
key.add_subkey(subkey, usage={KeyFlags.Authentication})
Loading Keys
------------
There are two ways to load keys: individually, or in a keyring.
Loading Keys Individually
^^^^^^^^^^^^^^^^^^^^^^^^^
Keys can be loaded individually into PGPKey objects::
# A new, empty PGPkey object can be instantiated, but this is not very useful
# by itself.
# ASCII or binary data can be parsed into an empty PGPKey object with the .parse()
# method
empty_key = pgpy.PGPKey()
empty_key.parse(keyblob)
# A key can be loaded from a file, like so:
key, _ = pgpy.PGPKey.from_file('path/to/key.asc')
# or from a text or binary string/bytes/bytearray that has already been read in:
key, _ = pgpy.PGPKey.from_blob(keyblob)
Loading Keys Into a Keyring
^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you intend to maintain multiple keys in memory for extended periods, using a PGPKeyring may be more appropriate::
# These two methods are mostly equivalent
kr = pgpy.PGPKeyring(glob.glob(os.path.expanduser('~/.gnupg/*ring.gpg')))
# the only advantage to doing it this way, is the .load method returns a set containing
# the fingerprints of all keys and subkeys that were loaded this time
kr = pgpy.PGPKeyring()
loaded = kr.load(glob.glob(os.path.expanduser('~/.gnupg/*ring.gpg')))
Key Operations
--------------
Once you have one or more keys generated or loaded, there are some things you may need or want to do before they can be used.
Passphrase Protecting Secret Keys
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It is usually recommended to passphrase-protect private keys. Adding a passphrase to a key is simple::
# key.is_public is False
# key.is_protected is False
key.protect("C0rrectPassphr@se", SymmetricKeyAlgorithm.AES256, HashAlgorithm.SHA256)
# key.is_protected is now True
Unlocking Protected Secret Keys
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you have a key that is protected with a passphrase, you will need to unlock it first. PGPy handles this using
a context manager block, which also removes the unprotected key material from the object once execution exits that block.
Key unlocking is quite simple::
# enc_key.is_public is False
# enc_key.is_protected is True
# enc_key.is_unlocked is False
# Note that this context manager yields self, so while you can supply `as cvar`, it isn't strictly required
# If the passphrase given is incorrect, this will raise PGPDecryptionError
with enc_key.unlock("C0rrectPassphr@se"):
# enc_key.is_unlocked is now True
...
# This form works equivalently, but may be more semantically clear in some cases:
with enc_key.unlock("C0rrectPassphr@se") as ukey:
# ukey is just a reference to enc_key in this case
...
Exporting Keys
^^^^^^^^^^^^^^
Keys can be exported in OpenPGP compliant binary or ASCII-armored formats.
In Python 3::
# binary
keybytes = bytes(key)
# ASCII armored
keystr = str(key)
in Python 2::
# binary
keybytes = key.__bytes__()
# ASCII armored
keystr = str(key)