PGPy Documentation¶
PGPy
is a Python implementation of the OpenPGP specification, as described in RFC 4880.
It aims to be easy to use above all else, but also to eventually embody a complete, compliant implementation of the specification.
Contents:
Installation¶
Platform Specific Notes¶
Windows¶
PGPy has not been formally tested on Windows. I see no reason why it wouldn’t work, but your mileage may vary. If you try it out and run into any issues, please submit bug reports on the issue tracker!
Linux¶
Gentoo¶
There are gentoo ebuilds available in the gentoo branch
RedHat/CentOS¶
Coming Soon!
Other Linux¶
Building PGPy on Linux requires a C compiler, headers for Python, headers for OpenSSL, and libffi, to support building Cryptography.
For Debian/Ubuntu, these requirements can be installed like so:
$ sudo apt install build-essential libssl-dev libffi-dev python-dev
For Alpine linux, the build requirements can be installed like so:
$ apk add build-base libressl-dev libffi-dev python-dev
You may need to install python3-dev
if you are using PGPy on Python 3.
For Fedora/RHEL derivatives, the build requirements can be installed like so:
$ sudo yum install gcc libffi-devel python-devel openssl-devel
Mac OS X¶
If you are on Mac OS, you may experience more limited functionality without installing a more capable version of OpenSSL.
You may refer to Cryptography’s documentation on Building cryptography on macOS for information on how to do so.
Installation¶
Once you have the prerequisites specified above, PGPy can be installed from PyPI using pip, like so:
$ pip install PGPy
Examples¶
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_expiration
keyword when adding the user id. Expiration can be specified
using a datetime.datetime
or a 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 1 year
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_expiration=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.RSAEncryptOrSign, 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 private key
keystr = str(key)
# ASCII armored public key
keystr = str(key.pubkey)
in Python 2:
# binary
keybytes = key.__bytes__()
# ASCII armored
keystr = str(key)
Messages¶
Other than plaintext, you may want to be able to form PGP Messages. These can be signed and then encrypted to one or more recipients.
Creating New Messages¶
New messages can be created quite easily:
# this creates a standard message from text
# it will also be compressed, by default with ZIP DEFLATE, unless otherwise specified
text_message = pgpy.PGPMessage.new("This is a brand spankin' new message!")
# if you'd like to pack a file into a message instead, you can do so
# PGPMessage will store the basename of the file and the time it was last modified.
file_message = pgpy.PGPMessage.new("path/to/a/file", file=True)
# or, if you want to create a *cleartext* message, which is what you may know as a
# canonicalized text document with an inline signature block, that is done by setting
# cleartext=True. You can load the contents of a file as above, as well.
ct_message = pgpy.PGPMessage.new("This is a shiny new cleartext document. Hooray!",
cleartext=True)
Loading Existing Messages¶
Existing messages can also be loaded very simply. This is nearly identical to loading keys, except that it only returns the new message object, instead of a tuple:
# PGPMessage will automatically determine if this is a cleartext message or not
message_from_file = pgpy.PGPMessage.from_file("path/to/a/message")
message_from_blob = pgpy.PGPMessage.from_blob(msg_blob)
Exporting Messages¶
Messages can be exported in OpenPGP compliant binary or ASCII-armored formats.
In Python 3:
# binary
msgbytes = bytes(message)
# ASCII armored
# if message is cleartext, this will also properly canonicalize and dash-escape
# the message text
msgstr = str(message)
in Python 2:
# binary
msgbytes = message.__bytes__()
# ASCII armored
# if message is cleartext, this will also properly canonicalize and dash-escape
# the message text
msgstr = str(message)
Actions¶
Signing Things¶
One of the things you may want to do with PGPKeys is to sign things. This is split into several categories in order to keep the method signatures relatively simple. Remember that signing requires a private key.
Text/Messages/Other¶
Text and messages can be signed using the .sign method:
# sign some text
sig = sec.sign("I have just signed this text!")
# sign a message
# the bitwise OR operator '|' is used to add a signature to a PGPMessage.
message |= sec.sign(message)
# timestamp signatures can also be generated, like so.
# Note that GnuPG seems to have no idea what to do with this
timesig = sec.sign(None)
# if optional parameters are supplied, then a standalone signature is created
# instead of a timestamp signature. Effectively, they are equivalent, except
# that the standalone signature has more information in it.
lone_sig = sec.sign(None, notation={"cheese status": "standing alone"})
Keys/User IDs¶
Keys and User IDs can be signed using the .certify method:
# Sign a key - this creates a Signature Directly On A Key.
# GnuPG only partially supports this type of signature.
someones_pubkey |= mykey.certify(someones_pubkey)
# Sign the primary User ID - this creates the usual certification signature
# that is best supported by other popular OpenPGP implementations.
# As above, the bitwise OR operator '|' is used to add a signature to a PGPUID.
cert = mykey.certify(someones_pubkey.userids[0], level=SignatureType.Persona_Cert)
someones_pubkey.userids[0] |= cert
# If you want to sign all of their User IDs, that can be done easily in a loop.
# This is equivalent to GnuPG's default behavior when signing someone's public key.
# As above, the bitwise OR operator '|' is used to add a signature to a PGPKey.
for uid in someones_pubkey.userids:
uid |= mykey.certify(uid)
Verifying Things¶
Although signing things uses multiple methods, there is only one method to remember for verifying signatures:
# verify a detached signature
pub.verify("I have just signed this text!", sig)
# verify signatures in a message
pub.verify(message)
# verify signatures on a userid
for uid in someones_pubkey.userids:
pub.verify(uid)
# or, better yet, verify all applicable signatures on a key in one go
pub.verify(someones_pubkey)
Encryption¶
Another thing you may want to do is encrypt or decrypt messages.
Encrypting/Decrypting Messages With a Public Key¶
Encryption using keys requires a public key, while decryption requires a private key. PGPy currently only supports asymmetric encryption/decryption using RSA or ECDH:
# Assume the sender has retrieved the public key and saved it to a file.
# reload the public key
pubkey, _ = PGPKey.from_file("PATH TO PUBLIC KEY FILE")
# As usual, construct a PGPMessage from a string:
message = PGPMessage.new("42 is quite a pleasant number")
# Transform it into a new PGPMessage that contains an encrypted form of the
# unencrypted message
encrypted_message = pubkey.encrypt(message)
# Recipient loads the private key
key, _ = PGPKey.from_file("PATH TO _PRIVATE_ KEY FILE")
# after the sender sends the encrypted message, the recipient decrypts:
plaintext = key.decrypt(encrypted_message).message
Encrypting Messages to Multiple Recipients¶
Warning
Care must be taken when doing this to delete the session key as soon as possible after encrypting the message.
Messages can also be encrypted to multiple recipients by pre-generating the session key:
# The symmetric cipher should be specified, in case the first preferred cipher is not
# the same for all recipients' public keys
cipher = pgpy.constants.SymmetricKeyAlgorithm.AES256
sessionkey = cipher.gen_key()
# encrypt the message to multiple recipients
# A decryption passphrase can be added at any point as well, as long as cipher
# and sessionkey are also provided to enc_msg.encrypt
enc_msg = pubkey1.encrypt(message, cipher=cipher, sessionkey=sessionkey)
enc_msg = pubkey2.encrypt(enc_msg, cipher=cipher, sessionkey=sessionkey)
# do at least this as soon as possible after encrypting to the final recipient
del sessionkey
Encrypting/Decrypting Messages With a Passphrase¶
There are some situations where encrypting a message with a passphrase may be more desirable than doing so with someone else’s public key. That can be done like so:
# the .encrypt method returns a new PGPMessage object which contains the encrypted
# contents of the old message
enc_message = message.encrypt("S00per_Sekr3t")
# message.is_encrypted is False
# enc_message.is_encrypted is True
# a message that was encrypted using a passphrase can also be decrypted using
# that same passphrase
dec_message = enc_message.decrypt("S00per_Sekr3t")
Ignoring Usage Flags¶
Warning
Don’t do this unless you’re really sure you need to!
Sometimes a key is created without the correct usage flags and an error is raised when you try to use the key:
>>> from pgpy import PGPKey, PGPMessage
>>> key, _ = PGPKey.from_file('path/to/key_without_usage_flags.asc')
>>> message = PGPMessage.new('secret message')
>>> encrypted_phrase = key.encrypt(message)
PGPError: Key 0123456789ABCDEF does not have the required usage flag EncryptStorage, EncryptCommunications
To disable this check, set _require_usage_flags
to False
on the key before calling the problem function:
>>> from pgpy import PGPKey, PGPMessage
>>> key, _ = PGPKey.from_file('path/to/key_without_usage_flags.asc')
>>> key._require_usage_flags = False
>>> message = PGPMessage.new('secret message')
>>> encrypted_phrase = key.encrypt(message)
Exporting PGP* Objects¶
PGPKey, PGPMessage, and PGPSignature objects can all be exported to OpenPGP-compatible binary and ASCII-armored formats.
To export in ASCII-armored format:
# This works in both Python 2.x and 3.x
# ASCII-armored format
# cleartext PGPMessages will also have properly canonicalized and dash-escaped
# message text
pgpstr = str(pgpobj)
To export to binary format in Python 3:
# binary format
pgpbytes = bytes(pgpobj)
To export to binary format in Python 2:
# binary format
pgpbytes = pgpobj.__bytes__()
PGPy API¶
Exceptions¶
PGPEncryptionError
¶
-
exception
pgpy.errors.
PGPEncryptionError
¶ Raised when encryption fails
PGPDecryptionError
¶
-
exception
pgpy.errors.
PGPDecryptionError
¶ Raised when decryption fails
PGPOpenSSLCipherNotSupported
¶
-
exception
pgpy.errors.
PGPOpenSSLCipherNotSupported
¶ Raised when OpenSSL does not support the requested cipher
PGPInsecureCipher
¶
-
exception
pgpy.errors.
PGPInsecureCipher
¶ Raised when a cipher known to be insecure is attempted to be used to encrypt data
WontImplementError
¶
-
exception
pgpy.errors.
WontImplementError
¶ Raised when something that is not implemented, will not be implemented
Constants¶
PubKeyAlgorithm
¶
-
class
pgpy.constants.
PubKeyAlgorithm
¶ Supported public key algorithms.
-
RSAEncryptOrSign
¶ Signifies that a key is an RSA key.
-
DSA
¶ Signifies that a key is a DSA key.
-
ElGamal
¶ Signifies that a key is an ElGamal key.
-
ECDH
¶ Signifies that a key is an ECDH key.
-
ECDSA
¶ Signifies that a key is an ECDSA key.
-
EllipticCurveOID
¶
-
class
pgpy.constants.
EllipticCurveOID
¶ OIDs for supported elliptic curves.
-
Curve25519
¶ DJB’s fast elliptic curve
-
Ed25519
¶ Twisted Edwards variant of Curve25519
-
NIST_P256
¶ NIST P-256, also known as SECG curve secp256r1
-
NIST_P384
¶ NIST P-384, also known as SECG curve secp384r1
-
NIST_P521
¶ NIST P-521, also known as SECG curve secp521r1
-
Brainpool_P256
¶ Brainpool Standard Curve, 256-bit
Note
Requires OpenSSL >= 1.0.2
-
Brainpool_P384
¶ Brainpool Standard Curve, 384-bit
Note
Requires OpenSSL >= 1.0.2
-
Brainpool_P512
¶ Brainpool Standard Curve, 512-bit
Note
Requires OpenSSL >= 1.0.2
-
SECP256K1
¶ SECG curve secp256k1
-
SymmetricKeyAlgorithm
¶
-
class
pgpy.constants.
SymmetricKeyAlgorithm
¶ Supported symmetric key algorithms.
-
IDEA
¶ Warning
IDEA is insecure. PGPy only allows it to be used for decryption, not encryption!
-
TripleDES
¶ Triple-DES with 168-bit key derived from 192
-
CAST5
¶ CAST5 (or CAST-128) with 128-bit key
-
Blowfish
¶ Blowfish with 128-bit key and 16 rounds
-
AES128
¶ AES with 128-bit key
-
AES192
¶ AES with 192-bit key
-
AES256
¶ AES with 256-bit key
-
Camellia128
¶ Camellia with 128-bit key
-
Camellia192
¶ Camellia with 192-bit key
-
Camellia256
¶ Camellia with 256-bit key
-
SignatureType
¶
-
class
pgpy.constants.
SignatureType
¶ Types of signatures that can be found in a Signature packet.
-
BinaryDocument
¶ The signer either owns this document, created it, or certifies that it has not been modified.
-
CanonicalDocument
¶ The signer either owns this document, created it, or certifies that it has not been modified. The signature is calculated over the text data with its line endings converted to
<CR><LF>
.
-
Standalone
¶ This signature is a signature of only its own subpacket contents. It is calculated identically to a signature over a zero-length
BinaryDocument
.
-
Generic_Cert
¶ The issuer of this certification does not make any particular claim as to how well the certifier has checked that the owner of the key is in fact the person described by the User ID.
-
Persona_Cert
¶ The issuer of this certification has not done any verification of the claim that the owner of this key is the User ID specified.
-
Casual_Cert
¶ The issuer of this certification has done some casual verification of the claim of identity.
-
Positive_Cert
¶ The issuer of this certification has done substantial verification of the claim of identity.
-
Attestation
¶ This signature is issued by the primary key over itself and its user ID (or user attribute). See draft-ietf-openpgp-rfc4880bis-08
-
Subkey_Binding
¶ This signature is a statement by the top-level signing key that indicates that it owns the subkey. This signature is calculated directly on the primary key and subkey, and not on any User ID or other packets.
-
PrimaryKey_Binding
¶ This signature is a statement by a signing subkey, indicating that it is owned by the primary key and subkey. This signature is calculated the same way as a
Subkey_Binding
signature.
-
DirectlyOnKey
¶ A signature calculated directly on a key. It binds the information in the Signature subpackets to the key, and is appropriate to be used for subpackets that provide information about the key, such as the Revocation Key subpacket. It is also appropriate for statements that non-self certifiers want to make about the key itself, rather than the binding between a key and a name.
-
KeyRevocation
¶ A signature calculated directly on the key being revoked. Only revocation signatures by the key being revoked, or by an authorized revocation key, should be considered valid revocation signatures.
-
SubkeyRevocation
¶ A signature calculated directly on the subkey being revoked. Only revocation signatures by the top-level signature key that is bound to this subkey, or by an authorized revocation key, should be considered valid revocation signatures.
-
CertRevocation
¶ This signature revokes an earlier User ID certification signature or direct-key signature. It should be issued by the same key that issued the revoked signature or an authorized revocation key. The signature is computed over the same data as the certificate that it revokes.
-
Timestamp
¶ This signature is only meaningful for the timestamp contained in it.
-
ThirdParty_Confirmation
¶ This signature is a signature over some other OpenPGP Signature packet(s). It is analogous to a notary seal on the signed data.
-
KeyFlags
¶
-
class
pgpy.constants.
KeyFlags
¶ Flags that determine a key’s capabilities.
-
Certify
¶ Signifies that a key may be used to certify keys and user ids. Primary keys always have this, even if it is not specified.
-
Sign
¶ Signifies that a key may be used to sign messages and documents.
-
EncryptCommunications
¶ Signifies that a key may be used to encrypt messages.
-
EncryptStorage
¶ Signifies that a key may be used to encrypt storage. Currently equivalent to
EncryptCommunications
.
-
Split
¶ Signifies that the private component of a given key may have been split by a secret-sharing mechanism. Split keys are not currently supported by PGPy.
-
Authentication
¶ Signifies that a key may be used for authentication.
-
MultiPerson
¶ Signifies that the private component of a key may be in the possession of more than one person.
-
RevocationReason
¶
-
class
pgpy.constants.
RevocationReason
¶ Reasons explaining why a key or certificate was revoked.
-
NotSpecified
¶ No reason was specified. This is the default reason.
-
Superseded
¶ The key was superseded by a new key. Only meaningful when revoking a key.
-
Compromised
¶ Key material has been compromised. Only meaningful when revoking a key.
-
Retired
¶ Key is retired and no longer used. Only meaningful when revoking a key.
-
UserID
¶ User ID information is no longer valid. Only meaningful when revoking a certification of a user id.
-
Classes¶
PGPKey
¶
-
class
pgpy.
PGPKey
¶ PGPKey objects represent OpenPGP compliant keys along with all of their associated data.
PGPKey implements the __str__ method, the output of which will be the key composition in OpenPGP-compliant ASCII-armored format.
PGPKey implements the __bytes__ method, the output of which will be the key composition in OpenPGP-compliant binary format.
Any signatures within the PGPKey that are marked as being non-exportable will not be included in the output of either of those methods.
-
ascii_headers
¶ An
OrderedDict
of headers that appear, in order, in the ASCII-armored form of this object.
-
classmethod
from_file
(filename)¶ Create a new
PGPKey
object, with contents loaded from a file. May be binary or ASCII armored.Parameters: filename ( str
) – The path to the file to load.Raises: ValueError
if a properly formed PGP block was not found in the file atfilename
Raises: PGPError
if de-armoring or parsing failedReturns: A two element tuple
ofPGPKey
,OrderedDict
. TheOrderedDict
has the following format:key, others = PGPKey.from_file('path/to/keyfile') # others: { (Fingerprint, bool(key.is_public)): PGPKey }
-
classmethod
from_blob
(blob)¶ Create a new
PGPKey
object, with contents loaded from a blob. May be binary or ASCII armored.Parameters: blob ( str
,bytes
,unicode
,bytearray
) – The data to load.Raises: TypeError
if blob is not in the expected types aboveRaises: ValueError
if a properly formed PGP block was not found inblob
Raises: PGPError
if de-armoring or parsing failedReturns: A two element tuple
ofPGPKey
,OrderedDict
. TheOrderedDict
has the following format:key, others = PGPKey.from_file('path/to/keyfile') # others: { (Fingerprint, bool(key.is_public)): PGPKey }
-
created
¶ A
datetime
object of the creation date and time of the key, in UTC.
-
expires_at
¶ A
datetime
object of when this key is to be considered expired, if any. Otherwise,None
-
fingerprint
¶ The fingerprint of this key, as a
Fingerprint
object.
-
is_expired
¶ True
if this key is expired, otherwiseFalse
-
is_primary
¶ True
if this is a primary key;False
if this is a subkey
-
is_protected
¶ True
if this is a private key that is protected with a passphrase, otherwiseFalse
-
is_public
¶ True
if this is a public key, otherwiseFalse
-
is_unlocked
¶ False
if this is a private key that is protected with a passphrase and has not yet been unlocked, otherwiseTrue
-
key_algorithm
¶ The
constants.PubKeyAlgorithm
pertaining to this key
-
key_size
¶ The size pertaining to this key.
int
for non-EC key algorithms;constants.EllipticCurveOID
for EC keys.New in version 0.4.1.
-
magic
¶ The magic string identifier for the current PGP type
-
pubkey
¶ If the
PGPKey
object is a private key, this method returns a corresponding public key object with all the trimmings. If it is already a public key, just return it.
-
signers
¶ A
set
of key ids of keys that were used to sign this key
-
subkeys
¶ An
OrderedDict
of subkeys bound to this primary key, if applicable, selected by 16-character keyid.
-
revocation_keys
¶ A
generator
with the list of keys that can revoke this key.See also
PGPSignature.revocation_key()
-
classmethod
new
(key_algorithm, key_size, created=None)¶ Generate a new PGP key
Parameters: - key_algorithm (
PubKeyAlgorithm
) – Key algorithm to use. - key_size (
int
orEllipticCurveOID
) – Key size in bits, unless key_algorithm isECDSA
orECDH
, in which case it should be the Curve OID to use. - created (
datetime
orNone
) – When was the key created? (None
or unset means now)
Returns: A newly generated
PGPKey
- key_algorithm (
-
protect
(passphrase, enc_alg, hash_alg)¶ Add a passphrase to a private key. If the key is already passphrase protected, it should be unlocked before a new passphrase can be specified.
Has no effect on public keys.
Parameters: - passphrase (
str
,unicode
) – A passphrase to protect the key with - enc_alg (
SymmetricKeyAlgorithm
) – Symmetric encryption algorithm to use to protect the key - hash_alg (
HashAlgorithm
) – Hash algorithm to use in the String-to-Key specifier
- passphrase (
-
unlock
(passphrase)¶ Context manager method for unlocking passphrase-protected private keys. Has no effect if the key is not both private and passphrase-protected.
When the context managed block is exited, the unprotected private key material is removed.
Example:
privkey = PGPKey() privkey.parse(keytext) assert privkey.is_protected assert privkey.is_unlocked is False # privkey.sign("some text") <- this would raise an exception with privkey.unlock("TheCorrectPassphrase"): # privkey is now unlocked assert privkey.is_unlocked # so you can do things with it sig = privkey.sign("some text") # privkey is no longer unlocked assert privkey.is_unlocked is False
Emits a
UserWarning
if the key is public or not passphrase protected.Parameters: passphrase ( str
) – The passphrase to be used to unlock this key.Raises: PGPDecryptionError
if the passphrase is incorrect
-
add_uid
(uid, selfsign=True, **prefs)¶ Add a User ID to this key.
Parameters: - uid (
PGPUID
) – The user id to add - selfsign (
bool
) – Whether or not to self-sign the user id before adding it
Valid optional keyword arguments are identical to those of self-signatures for
PGPKey.certify()
. Any such keyword arguments are ignored if selfsign isFalse
- uid (
-
get_uid
(search)¶ Find and return a User ID that matches the search string given.
Parameters: search ( str
,unicode
) – A text string to match name, comment, or email address againstReturns: The first matching PGPUID
, orNone
if no matches were found.
-
del_uid
(search)¶ Find and remove a user id that matches the search string given. This method does not modify the corresponding
PGPUID
object; it only removes it from the list of user ids on the key.Parameters: search ( str
,unicode
) – A text string to match name, comment, or email address against
-
add_subkey
(key, **prefs)¶ Add a key as a subkey to this key.
Parameters: Other valid optional keyword arguments are identical to those of self-signatures for
PGPKey.certify()
-
sign
(subject, **prefs)¶ Sign text, a message, or a timestamp using this key.
Parameters: subject ( str
,PGPMessage
,None
) – The text to be signedRaises: PGPError
if the key is passphrase-protected and has not been unlockedRaises: PGPError
if the key is publicReturns: PGPSignature
The following optional keyword arguments can be used with
PGPKey.sign()
, as well asPGPKey.certify()
,PGPKey.revoke()
, andPGPKey.bind()
:Parameters: - expires (
datetime
,timedelta
) – Set an expiration date for this signature - notation (
dict
) – Add arbitrary notation data to this signature. - policy_uri (
str
) – Add a URI to the signature that should describe the policy under which the signature was issued. - revocable (
bool
) – IfFalse
, this signature will be marked non-revocable - user (
str
) – Specify which User ID to use when creating this signature. Also adds a “Signer’s User ID” to the signature. - created (
datetime
) – Specify the time that the signature should be made. If unset or None, it will use the present time. - intended_recipients (
list
) – Specify a list ofPGPKey
objects that will be encrypted to. - include_issuer_fingerprint (
bool
) – Whether to include a hashed subpacket indicating the issuer fingerprint. (only for v4 keys, defaults to True)
- expires (
-
certify
(subject, level=SignatureType.Generic_Cert, **prefs)¶ Sign a key or a user id within a key.
Parameters: - subject (
PGPKey
,PGPUID
) – The user id or key to be certified. - level –
Generic_Cert
,Persona_Cert
,Casual_Cert
, orPositive_Cert
. Only used if subject is aPGPUID
; otherwise, it is ignored.
Raises: PGPError
if the key is passphrase-protected and has not been unlockedRaises: PGPError
if the key is publicReturns: In addition to the optional keyword arguments accepted by
PGPKey.sign()
, the following optional keyword arguments can be used withPGPKey.certify()
.These optional keywords only make sense, and thus only have an effect, when self-signing a key or User ID:
Parameters: - usage (
set
) – Aset
of key usage flags, asKeyFlags
. This keyword is ignored for non-self-certifications. - ciphers (
list
) – A list of preferred symmetric ciphers, asSymmetricKeyAlgorithm
. This keyword is ignored for non-self-certifications. - hashes (
list
) – A list of preferred hash algorithms, asHashAlgorithm
. This keyword is ignored for non-self-certifications. - compression (
list
) – A list of preferred compression algorithms, asCompressionAlgorithm
. This keyword is ignored for non-self-certifications. - key_expiration (
datetime.datetime
,datetime.timedelta
) – Specify a key expiration date for when this key should expire, or atimedelta
of how long after the key was created it should expire. This keyword is ignored for non-self-certifications. - attested_certifications (
list
) – A list of third-party certifications, asPGPSignature
, that the certificate holder wants to attest to for redistribution with the certificate. Alternatively, any element in the list can be abytes
orbytearray
object of the appropriate length (the length of this certification’s digest). This keyword is only used for signatures of type Attestation. - keyserver (
str
,unicode
,bytes
) – Specify the URI of the preferred key server of the user. This keyword is ignored for non-self-certifications. - keyserver_flags (
set
) – A set of Key Server Preferences, asKeyServerPreferences
. - primary (
bool
) – Whether or not to consider the certified User ID as the primary one. This keyword is ignored for non-self-certifications, and any certifications directly on keys.
These optional keywords only make sense, and thus only have an effect, when signing another key or User ID:
Parameters: - trust (
tuple
of twoint
s) – Specify the level and amount of trust to assert when certifying a public key. Should be a tuple of twoint
s, specifying the trust level and trust amount. See RFC 4880 Section 5.2.3.13. Trust Signature for more on what these values mean. - regex (
str
) – Specify a regular expression to constrain the specified trust signature in the resulting signature. Symbolically signifies that the specified trust signature only applies to User IDs which match this regular expression. This is meaningless without also specifying trust level and amount. - exportable (
bool
) – Whether this certification is exportable or not.
- subject (
-
revoke
(target, **prefs)¶ Revoke a key, a subkey, or all current certification signatures of a User ID that were generated by this key so far.
Parameters: target ( PGPKey
,PGPUID
) – The key to revokeRaises: PGPError
if the key is passphrase-protected and has not been unlockedRaises: PGPError
if the key is publicReturns: PGPSignature
In addition to the optional keyword arguments accepted by
PGPKey.sign()
, the following optional keyword arguments can be used withPGPKey.revoke()
.Parameters: - reason (One of
constants.RevocationReason
.) – Defaults toconstants.RevocationReason.NotSpecified
- comment (
str
) – Defaults to an empty string.
- reason (One of
-
revoker
(revoker, **prefs)¶ Generate a signature that specifies another key as being valid for revoking this key.
Parameters: revoker ( PGPKey
) – ThePGPKey
to specify as a valid revocation key.Raises: PGPError
if the key is passphrase-protected and has not been unlockedRaises: PGPError
if the key is publicReturns: PGPSignature
In addition to the optional keyword arguments accepted by
PGPKey.sign()
, the following optional keyword arguments can be used withPGPKey.revoker()
.Parameters: sensitive ( bool
) – IfTrue
, this sets the sensitive flag on the RevocationKey subpacket. Currently, this has no other effect.
-
bind
(key, **prefs)¶ Bind a subkey to this key.
In addition to the optional keyword arguments accepted for self-signatures by
PGPkey.certify()
, the following optional keyword arguments can be used withPGPKey.bind()
.Parameters: crosssign ( bool
) – IfFalse
, do not attempt a cross-signature (defaults toTrue
). Subkeys which are not capable of signing will not produce a cross-signature in any case. Settingcrosssign
toFalse
is likely to produce subkeys that will be rejected by some other OpenPGP implementations.
-
verify
(subject, signature=None)¶ Verify a subject with a signature using this key.
Parameters: - subject (
str
,unicode
,None
,PGPMessage
,PGPKey
,PGPUID
) – The subject to verify - signature (
PGPSignature
) – If the signature is detached, it should be specified here.
Returns: - subject (
-
encrypt
(message, [sessionkey=None, ]**prefs)¶ Encrypt a PGPMessage using this key.
Parameters: - message (
PGPMessage
) – The message to encrypt. - sessionkey (
bytes
,str
) –Provide a session key to use when encrypting something. Default is
None
. IfNone
, a session key of the appropriate length will be generated randomly.Warning
Care should be taken when making use of this option! Session keys absolutely need to be unpredictable! Use the
gen_key()
method on the desiredSymmetricKeyAlgorithm
to generate the session key!
Raises: PGPEncryptionError
if encryption failed for any reason.Returns: A new
PGPMessage
with the encrypted contents ofmessage
The following optional keyword arguments can be used with
PGPKey.encrypt()
:Parameters: - cipher (
SymmetricKeyAlgorithm
) – Specifies the symmetric block cipher to use when encrypting the message. - user (
str
,unicode
) – Specifies the User ID to use as the recipient for this encryption operation, for the purposes of preference defaults and selection validation.
- message (
-
decrypt
(message)¶ Decrypt a PGPMessage using this key.
Parameters: message – An encrypted PGPMessage
Raises: PGPError
if the key is not private, or protected but not unlocked.Raises: PGPDecryptionError
if decryption fails for any other reason.Returns: A new PGPMessage
with the decrypted contents ofmessage
.
-
parse
(data)¶ this method is too abstract to understand
-
PGPKeyring
¶
-
class
pgpy.
PGPKeyring
¶ PGPKeyring objects represent in-memory keyrings that can contain any combination of supported private and public keys. It can not currently be conveniently exported to a format that can be understood by GnuPG.
-
ascii_headers
¶ An
OrderedDict
of headers that appear, in order, in the ASCII-armored form of this object.
-
load
(*args)¶ Load all keys provided into this keyring object.
Parameters: *args ( list
,tuple
,str
,unicode
,bytes
,bytearray
) – Each arg inargs
can be any of the formats supported byPGPKey.from_file()
andPGPKey.from_blob()
or aPGPKey
instance, or alist
ortuple
of these.Returns: a set
containing the unique fingerprints of all of the keys that were loaded during this operation.
-
key
(identifier)¶ A context-manager method. Yields the first
PGPKey
object that matches the provided identifier.Parameters: identifier ( PGPMessage
,PGPSignature
,str
) – The identifier to use to select a loaded key.Raises: KeyError
if there is no loaded key that satisfies the identifier.
-
fingerprints
(keyhalf='any', keytype='any')¶ List loaded fingerprints with some optional filtering.
Parameters: - keyhalf (
str
) – Can be ‘any’, ‘public’, or ‘private’. If ‘public’, or ‘private’, the fingerprints of keys of the the other type will not be included in the results. - keytype (
str
) – Can be ‘any’, ‘primary’, or ‘sub’. If ‘primary’ or ‘sub’, the fingerprints of keys of the the other type will not be included in the results.
Returns: a
set
of fingerprints of keys matching the filters specified.- keyhalf (
-
unload
(key)¶ Unload a loaded key and its subkeys.
Parameters: key ( PGPKey
) – The key to unload.The easiest way to do this is to select a key using
PGPKeyring.key()
first:with keyring.key("DSA von TestKey") as key: keyring.unload(key)
-
PGPMessage
¶
-
class
pgpy.
PGPMessage
¶ PGPMessage objects represent OpenPGP message compositions.
PGPMessage implements the
__str__
method, the output of which will be the message composition in OpenPGP-compliant ASCII-armored format.PGPMessage implements the
__bytes__
method, the output of which will be the message composition in OpenPGP-compliant binary format.Any signatures within the PGPMessage that are marked as being non-exportable will not be included in the output of either of those methods.
-
ascii_headers
¶ An
OrderedDict
of headers that appear, in order, in the ASCII-armored form of this object.
-
classmethod
from_file
(filename)¶ Create a new
PGPMessage
object, with contents loaded from a file. May be binary or ASCII armored.Parameters: filename ( str
) – The path to the file to load.Raises: ValueError
if a properly formed PGP block was not found in the file atfilename
Raises: PGPError
if de-armoring or parsing failedReturns: PGPMessage
-
classmethod
from_blob
(blob)¶ Create a new
PGPMessage
object, with contents loaded from a blob. May be binary or ASCII armored.Parameters: blob ( str
,bytes
,unicode
,bytearray
) – The data to load.Raises: TypeError
if blob is not in the expected types aboveRaises: ValueError
if a properly formed PGP block was not found inblob
Raises: PGPError
if de-armoring or parsing failedReturns: PGPMessage
-
encrypters
¶ A
set
containing all key ids (if any) to which this message was encrypted.
-
filename
¶ If applicable, returns the original filename of the message. Otherwise, returns an empty string.
-
is_compressed
¶ True
if this message will be compressed when exported
-
is_encrypted
¶ True
if this message is encrypted; otherwise,False
-
is_sensitive
¶ True
if this message is marked sensitive; otherwiseFalse
-
is_signed
¶ True
if this message is signed; otherwise,False
. Should always beFalse
if the message is encrypted.
-
issuers
¶ A
set
containing all key ids (if any) which have signed or encrypted this message.
-
magic
¶ The magic string identifier for the current PGP type
-
message
¶ The message contents
-
signatures
¶ A
set
containing all key ids (if any) which have signed this message.
-
signers
¶ A
set
containing all key ids (if any) which have signed this message.
-
classmethod
new
(message, **kwargs)¶ Create a new PGPMessage object.
Parameters: message ( str
,unicode
,bytes
,bytearray
) – The message to be stored.Returns: PGPMessage
The following optional keyword arguments can be used with
PGPMessage.new()
:Parameters: - file (
bool
) – if True,message
should be a path to a file. The contents of that file will be read and used as the contents of the message. - cleartext (
bool
) – if True, the message will be cleartext with inline signatures. - sensitive (
bool
) – if True, the filename will be set to ‘_CONSOLE’ to signal other OpenPGP clients to treat this message as being ‘for your eyes only’. Ignored if cleartext is True. - format (
str
) – Set the message format identifier. Ignored if cleartext is True. - compression – Set the compression algorithm for the new message.
Defaults to
CompressionAlgorithm.ZIP
. Ignored if cleartext is True. - encoding (
str
representing a valid codec in codecs) – Set the Charset header for the message.
- file (
-
encrypt
(passphrase, [sessionkey=None, ]**prefs)¶ Encrypt the contents of this message using a passphrase.
Parameters: - passphrase (
str
,unicode
,bytes
) – The passphrase to use for encrypting this message. - sessionkey (
bytes
,str
) –Provide a session key to use when encrypting something. Default is
None
. IfNone
, a session key of the appropriate length will be generated randomly.Warning
Care should be taken when making use of this option! Session keys absolutely need to be unpredictable! Use the
gen_key()
method on the desiredSymmetricKeyAlgorithm
to generate the session key!
Raises: Returns: A new
PGPMessage
containing the encrypted contents of this message.- passphrase (
-
decrypt
(passphrase)¶ Attempt to decrypt this message using a passphrase.
Parameters: passphrase ( str
,unicode
,bytes
) – The passphrase to use to attempt to decrypt this message.Raises: PGPDecryptionError
if decryption failed for any reason.Returns: A new PGPMessage
containing the decrypted contents of this message
-
parse
(packet)¶ this method is too abstract to understand
-
PGPSignature
¶
-
class
pgpy.
PGPSignature
¶ PGPSignature objects represent OpenPGP compliant signatures.
PGPSignature implements the
__str__
method, the output of which will be the signature object in OpenPGP-compliant ASCII-armored format.PGPSignature implements the
__bytes__
method, the output of which will be the signature object in OpenPGP-compliant binary format.-
ascii_headers
¶ An
OrderedDict
of headers that appear, in order, in the ASCII-armored form of this object.
-
classmethod
from_file
(filename)¶ Create a new
PGPSignature
object, with contents loaded from a file. May be binary or ASCII armored.Parameters: filename ( str
) – The path to the file to load.Raises: ValueError
if a properly formed PGP block was not found in the file atfilename
Raises: PGPError
if de-armoring or parsing failedReturns: PGPSignature
-
classmethod
from_blob
(blob)¶ Create a new
PGPSignature
object, with contents loaded from a blob. May be binary or ASCII armored.Parameters: blob ( str
,bytes
,unicode
,bytearray
) – The data to load.Raises: TypeError
if blob is not in the expected types aboveRaises: ValueError
if a properly formed PGP block was not found inblob
Raises: PGPError
if de-armoring or parsing failedReturns: PGPSignature
-
cipherprefs
¶ A
list
of preferred symmetric algorithms specified in this signature, if any. Otherwise, an emptylist
.
-
compprefs
¶ A
list
of preferred compression algorithms specified in this signature, if any. Otherwise, an emptylist
.
-
created
¶ A
datetime
of when this signature was created.
-
expires_at
¶ A
datetime
of when this signature expires, if a signature expiration date is specified. Otherwise,None
-
exportable
¶ False
if this signature is marked as being not exportable. Otherwise,True
.
-
features
¶ A
set
of implementation features specified in this signature, if any. Otherwise, an emptyset
.
-
hashprefs
¶ A
list
of preferred hash algorithms specified in this signature, if any. Otherwise, an emptylist
.
-
hash_algorithm
¶ The
HashAlgorithm
used when computing this signature.
-
is_expired
¶ True
if the signature has an expiration date, and is expired. Otherwise,False
-
key_algorithm
¶ The
PubKeyAlgorithm
of the key that generated this signature.
-
keyserver
¶ The preferred key server specified in this signature, if any. Otherwise, an empty
str
.
-
keyserverprefs
¶ A
list
ofKeyServerPreferences
in this signature, if any. Otherwise, an emptylist
.
-
magic
¶ The magic string identifier for the current PGP type
-
notation
¶ A
dict
of notation data in this signature, if any. Otherwise, an emptydict
.
-
policy_uri
¶ The policy URI specified in this signature, if any. Otherwise, an empty
str
.
-
revocable
¶ False
if this signature is marked as being not revocable. Otherwise,True
.
-
attested_certifications
¶ Returns a set of all the hashes of attested certifications covered by this Attestation Key Signature.
Unhashed subpackets are ignored.
-
signer
¶ The 16-character Key ID of the key that generated this signature.
-
signer_fingerprint
¶ The fingerprint of the key that generated this signature, if it contained. Otherwise, an empty
str
.
-
intended_recipients
¶ Returns an iterator over all the primary key fingerprints marked as intended encrypted recipients for this signature.
-
type
¶ The
SignatureType
of this signature.
-
attests_to
(othersig)¶ returns True if this signature attests to othersig (acknolwedges it for redistribution)
-
parse
(packet)¶ this method is too abstract to understand
-
PGPUID
¶
-
class
pgpy.
PGPUID
¶ PGPUID objects represent User IDs and User Attributes for keys.
PGPUID implements the
__format__
method for User IDs, returning a string in the format ‘name (comment) <email>’, leaving out any comment or email fields that are not present.-
name
¶ If this is a User ID, the stored name. If this is not a User ID, this will be an empty string.
-
comment
¶ If this is a User ID, this will be the stored comment. If this is not a User ID, or there is no stored comment, this will be an empty string.,
-
email
¶ If this is a User ID, this will be the stored email address. If this is not a User ID, or there is no stored email address, this will be an empty string.
-
userid
¶ If this is a User ID, this will be the full UTF-8 string. If this is not a User ID, this will be
None
.
-
image
¶ If this is a User Attribute, this will be the stored image. If this is not a User Attribute, this will be
None
.
-
is_primary
¶ If the most recent, valid self-signature specifies this as being primary, this will be True. Otherwise, False.
-
is_uid
¶ True
if this is a User ID, otherwise False.
-
is_ua
¶ True
if this is a User Attribute, otherwise False.
-
selfsig
¶ This will be the most recent, self-signature of this User ID or Attribute. If there isn’t one, this will be
None
.
-
signers
¶ This will be a set of all of the key ids which have signed this User ID or Attribute.
-
third_party_certifications
¶ A generator returning all third-party certifications
-
attested_to
(certifications)¶ filter certifications, only returning those that have been attested to by the first party
-
attested_third_party_certifications
¶ A generator that provides a list of all third-party certifications attested to by the primary key.
-
classmethod
new
(pn, comment='', email='')¶ Create a new User ID or photo.
Parameters: - pn (
bytearray
,str
,unicode
) – User ID name, or photo. If this is abytearray
, it will be loaded as a photo. Otherwise, it will be used as the name field for a User ID. - comment (
str
,unicode
) – The comment field for a User ID. Ignored if this is a photo. - email (
str
,unicode
) – The email address field for a User ID. Ignored if this is a photo.
Returns: - pn (
-
Other Objects¶
These are objects that are returned during certain operations, but are probably not useful to instantiate directly.
SignatureVerification
¶
-
class
pgpy.types.
SignatureVerification
¶ Returned by
PGPKey.verify()
Can be compared directly as a boolean to determine whether or not the specified signature verified.
-
good_signatures
¶ A generator yielding namedtuples of all signatures that were successfully verified in the operation that returned this instance. The namedtuple has the following attributes:
sigsubj.verified
-bool
of whether the signature verified successfully or not.sigsubj.by
- thePGPKey
that was used in this verify operation.sigsubj.signature
- thePGPSignature
that was verified.sigsubj.subject
- the subject that was verified using the signature.
-
bad_signatures
¶ A generator yielding namedtuples of all signatures that were not verified in the operation that returned this instance. The namedtuple has the following attributes:
sigsubj.verified
-bool
of whether the signature verified successfully or not.sigsubj.by
- thePGPKey
that was used in this verify operation.sigsubj.signature
- thePGPSignature
that was verified.sigsubj.subject
- the subject that was verified using the signature.
-
Fingerprint
¶
-
class
pgpy.types.
Fingerprint
¶ A subclass of
str
. Can be compared using == and != tostr
,unicode
, and otherFingerprint
instances.Primarily used as a key for internal dictionaries, so it ignores spaces when comparing and hashing
OpenPGP Implementation Progress¶
OpenPGP RFCs¶
PGPy is focused on eventually reaching complete OpenPGP implementation, adhering to the base OpenPGP message format specification, and its extension RFCs.
RFC 4880¶
PGPy is currently focused on achieving RFC 4880 compliance for OpenPGP, which is the latest complete OpenPGP Message Format specification. It supersedes RFC 1991 and RFC 2440.
Progress | |
---|---|
Versioned Packets, v1 | |
✓ | Tag 18 Symetrically Encrypted and Integrity Protected Data Packet |
Versioned Packets, v3 | |
✓ | Tag 1 Public-Key Encrypted Session Key Packets |
Tag 2 Signature Packet | |
✓ | Tag 4 One-Pass Signature Packet |
Tag 5 Secret-Key Packet | |
Tag 6 Public-Key Packet | |
Tag 7 Secret-Subkey Packet | |
Tag 14 Public-SubKey Packet | |
Versioned Packets, v4 | |
✓ | Tag 2 Signature Packet |
✓ | Tag 3 Symmetric-Key Encrypted Session Key Packet |
✓ | Tag 5 Secret-Key Packet |
✓ | Tag 6 Public-Key Packet |
✓ | Tag 7 Secret-Subkey Packet |
✓ | Tag 14 Public-SubKey Packet |
Unversioned Packets | |
✓ | Tag 8 Compressed Data Packet |
✓ | Tag 9 Symetrically Encrypted Data Packet |
✓ | Tag 10 Marker Packet |
✓ | Tag 11 Literal Data Packet |
✓ | Tag 12 Trust Packet |
✓ | Tag 13 User ID Packet |
✓ | Tag 17 User Attribute Packet |
✓ | Tag 19 Modification Detection Code Packet |
Signature Subpackets | |
✓ | 0x02 Signature Creation Time |
✓ | 0x03 Signature Expiration Time |
✓ | 0x04 Exportable Certification |
✓ | 0x05 Trust Signature |
✓ | 0x06 Regular Expression |
✓ | 0x07 Revocable |
✓ | 0x09 Key Expiration Time |
✓ | 0x0B Preferred Symmetric Algorithms |
✓ | 0x0C Revocation Key |
✓ | 0x10 Issuer |
✓ | 0x14 Notation Data |
✓ | 0x15 Preferred Hash Algorithms |
✓ | 0x16 Preferred Compression Algorithms |
✓ | 0x17 Key Server Preferences |
✓ | 0x18 Preferred Key Server |
✓ | 0x19 Primary User ID |
✓ | 0x1A Policy URI |
✓ | 0x1B Key Flags |
✓ | 0x1C Signer’s User ID |
✓ | 0x1D Reason For Revocation |
✓ | 0x1E Features |
0x1F Signature Target | |
✓ | 0x20 Embedded Signature |
User Attribute Subpackets | |
✓ | 0x01 Image |
Storage Formats | |
✓ | ASCII ASCII armored PGP blocks |
✓ | binary binary PGP packets |
✓ | GPG GPG <= 2.0.x keyrings |
KBX GPG >= 2.1.x keyboxes | |
Other Sources | |
Retrieve Retrieve from HKP key servers | |
Upload Submit to HKP key servers | |
Key Types | |
✓ | RSA RSA |
✓ | DSA DSA |
✓ | ElGamal ElGamal |
Key Actions | |
✓ | Protect Protect private keys encryped with CAST5 |
✓ | Protect Protect private keys encryped with Blowfish |
✓ | Protect Protect private keys encryped with AES |
Protect Protect private keys encryped with Twofish | |
✓ | Unprotect Unprotect private keys encrypted with IDEA [1] |
✓ | Unprotect Unprotect private keys encrypted with Triple-DES |
✓ | Unprotect Unprotect private keys encrypted with CAST5 |
✓ | Unprotect Unprotect private keys encrypted with Blowfish |
✓ | Unprotect Unprotect private keys encrypted with AES |
Unprotect Unprotect private keys encrypted with Twofish | |
RSA Key Actions | |
✓ | Load Load Keys |
✓ | Generate Generate Keys |
✓ | Generate Generate Subkeys |
✓ | Sign Generate detached signatures of binary documents |
✓ | Sign Generate inline signatures of canonical documents |
✓ | Sign Sign messages |
✓ | Sign Sign keys |
✓ | Sign Certify User IDs |
✓ | Sign Certify User Attributes |
✓ | Sign Generate key binding signatures |
✓ | Sign Revoke certifications |
✓ | Sign Revoke keys |
✓ | Sign Revoke subkeys |
✓ | Sign Generate timestamp signatures |
✓ | Sign Generate standalone signatures |
Sign Generate third party confirmation signatures | |
✓ | Verify Verify detached signatures |
✓ | Verify Verify inline signatures of canonical documents |
✓ | Verify Verify messages |
✓ | Verify Verify key signatures |
✓ | Verify Verify User ID certification signatures |
✓ | Verify Verify User Attribute certification signatures |
✓ | Verify Verify key binding signatures |
✓ | Verify Verify key revocation signatures |
✓ | Verify Verify subkey revocation signatures |
✓ | Verify Verify certification revocation signatures |
✓ | Verify Verify timestamp signatures |
✓ | Verify Verify standalone signatures |
Verify Verify third party confirmation signatures | |
✓ | Revocation Designate Revocation Key |
✓ | Revocation Revoke (Sub)Key with Self Signature |
Revocation Revoke (Sub)Key using Designated Revocation Key | |
✓ | Encryption Encrypt data/messages |
✓ | Decryption Decrypt data/messages |
DSA Key Actions | |
✓ | Load Load Keys |
✓ | Generate Generate Keys |
✓ | Generate Generate Subkeys |
✓ | Sign Generate detached signatures of binary documents |
✓ | Sign Generate inline signatures of canonical documents |
✓ | Sign One-Pass Sign messages |
✓ | Sign Sign messages |
✓ | Sign Sign keys |
✓ | Sign Certify User IDs |
✓ | Sign Certify User Attributes |
✓ | Sign Generate key binding signatures |
✓ | Sign Revoke certifications |
✓ | Sign Revoke keys |
✓ | Sign Revoke subkeys |
✓ | Sign Generate timestamp signatures |
✓ | Sign Generate standalone signatures |
Sign Generate third party confirmation signatures | |
✓ | Verify Verify detached signatures |
✓ | Verify Verify inline signatures of canonical documents |
✓ | Verify Verify messages |
✓ | Verify Verify key signatures |
✓ | Verify Verify User ID certification signatures |
✓ | Verify Verify User Attribute certification signatures |
✓ | Verify Verify key binding signatures |
✓ | Verify Verify key revocation signatures |
✓ | Verify Verify subkey revocation signatures |
✓ | Verify Verify certification revocation signatures |
✓ | Verify Verify timestamp signatures |
✓ | Verify Verify standalone signatures |
Verify Verify third party confirmation signatures | |
✓ | Revocation Designate Revocation Key |
✓ | Revocation Revoke (Sub)Key with Self Signature |
Revocation Revoke (Sub)Key using Designated Revocation Key | |
ElGamal Key Actions | |
✓ | Load Load Keys |
Generate Generate Keys | |
Generate Generate Subkeys | |
Encryption Encrypt data/messages | |
Decryption Decrypt data/messages | |
Other Actions | |
✓ | Encryption Encrypt data/messages using symmetric ciphers with passphrases |
✓ | Decryption Decrypt data/messages using symmetric ciphers with passphrases |
RFC 4398¶
RFC 4398 covers publishing and retrieving PGP public keys via DNS CERT records.
Progress | |
---|---|
Key Sources | |
DNS CERT Look up and retrieve keys stored in Content-based DNS CERT records | |
DNS CERT Look up and retrieve keys stored in Purpose-based DNS CERT records |
RFC 5581¶
RFC 5581 extends RFC 4880 to officially add support for the Camellia cipher
Progress | |
---|---|
Actions | |
✓ | Encryption Camellia [1] |
✓ | Decryption Camellia [1] |
RFC 6637¶
RFC 6637 extends OpenPGP to officially add support for elliptic curve cryptography
Progress | |
---|---|
Key Types | |
✓ | ECDH Elliptic Curve Diffie-Hellman |
✓ | ECDSA Elliptic Curve Digital Signature Algorithm |
Curves | |
✓ | Curve NIST P-256 |
✓ | Curve NIST P-386 |
✓ | Curve NIST P-521 |
ECDH Key Actions | |
✓ | Load Load Keys |
✓ | Generate Generate Keys |
✓ | Generate Generate Subkeys |
✓ | KDF Encode KDF data for encryption |
✓ | KDF Decode KDF data for decryption |
ECDSA Key Actions | |
✓ | Load Load Keys |
✓ | Generate Generate Keys |
✓ | Generate Generate Subkeys |
✓ | Sign Generate detached signatures of binary documents |
✓ | Sign Generate inline signatures of canonical documents |
✓ | Sign One-Pass Sign messages |
✓ | Sign Sign messages |
✓ | Sign Sign keys |
✓ | Sign Certify User IDs |
✓ | Sign Certify User Attributes |
✓ | Sign Generate key binding signatures |
✓ | Sign Revoke certifications |
✓ | Sign Revoke keys |
✓ | Sign Revoke subkeys |
✓ | Sign Generate timestamp signatures |
✓ | Sign Generate standalone signatures |
Sign Generate third party confirmation signatures | |
✓ | Verify Verify detached signatures |
✓ | Verify Verify inline signatures of canonical documents |
✓ | Verify Verify messages |
✓ | Verify Verify key signatures |
✓ | Verify Verify Use r ID certification signatures |
✓ | Verify Verify User Attribute certification signatures |
✓ | Verify Verify key binding signatures |
✓ | Verify Verify key revocation signatures |
✓ | Verify Verify subkey revocation signatures |
✓ | Verify Verify certification revocation signatures |
✓ | Verify Verify timestamp signatures |
✓ | Verify Verify standalone signatures |
Verify Verify third party confirmation signatures | |
✓ | Revocation Designate Revocation Key |
✓ | Revocation Revoke (Sub)Key with Self Signature |
Revocation Revoke (Sub)Key using Designated Revocation Key |
Non-RFC Extensions¶
This section covers things that are considered extensions to PGP, but are not codified in the form of an RFC.
DNS PKA¶
Publishing OpenPGP keys in DNS
Progress | |
---|---|
Other Sources | |
DNS PKA Look up and retrieve keys stored in DNS PKA records. |
OpenPGP HTTP Keyserver Protocol (HKP)¶
The protocol is specified in Marc Horowitz’s thesis paper, and an expired RFC draft by David Shaw, draft-shaw-openpgp-hkp-00.
Progress | |
---|---|
HKP | |
Discovery Round robin DNS and SRV lookups (section 7. Locating a HKP Keyserver) | |
Index Look up keys on key server, with multiple possible matches (section 3.1.2.2. The “index” Operation) | |
Get Retrieve keys from key server, single fingerprint fetch (section 3.1.2.1. The “get” operation) | |
Post Send keys to key server (section 4. Submitting Keys To A Keyserver) |
OpenPGP Web Key Service (WKS)¶
LocatesOpenPGP keys by mail address using a Web service and the HTTPS protocol. Protocol specified in an in-progress RFC draft by Werner Koch, draft-koch-openpgp-webkey-service
Progress | |
---|---|
WKS | |
Discovery Fetches keys matching a UID from the server, using DNS and SRV lookups (section 3.1. Key Discovery) | |
Update Update keys on the WKS (section 4. Web Key Directory Update Protocol) |
EdDSA for OpenPGP¶
Use of Ed25519 with ECDSA and ECDH in OpenPGP is currently specified in an in-progress RFC draft by Werner Koch, draft-ietf-openpgp-rfc4880bis.
Progress | |
---|---|
Curves | |
✓ | Curve Ed25519 |
✓ | Curve X25519 |
Additional Curves for OpenPGP¶
Some additional curves that can be used with ECDSA/ECDH that are not explicitly called out in RFC 6637, but have standardized OIDs and are implemented in other software.
Progress | |
---|---|
Curves | |
✓ | Curve Brainpool P-256 |
✓ | Curve Brainpool P-384 |
✓ | Curve Brainpool P-512 |
✓ | Curve Curve25519 [1] |
✓ | Curve SECP256K1 |
Note
Use of Brainpool curves with ECDSA/ECDH
Although these curves are not explicitly mentioned in an RFC for OpenPGP at this point, GnuPG 2.1.x+ does support using them. As such, they have been included here.
[1] | (1, 2, 3, 4) Cipher availability depends on the currently installed OpenSSL being compiled with support for it |
Changelog¶
v0.5.4¶
Released: April 16, 2021
Note
PGPy v0.5.x is still compatible with Python 2.7 and 3.4. Support for those versions will be dropped in PGPy v0.6.0.
Bugs Fixed¶
- Fixed compatibility break with Python < 3.8 (#368)
- Fixed importing ABCs from
collections
(#328)
Other Changes¶
- Documentation updates
v0.5.3¶
Released: October 6, 2020
Warning
This is the last release that will support Python 2.7 and 3.4. Future releases will require Python 3.5 or greater.
Bugs fixed¶
- Passphrases are now encoded as utf-8 instead of latin-1 (#294)
- PGPUIDs without a selfsig no longer cause crashes (#315)
- Fixed dash un-escaping to be applied unconditionally (#341, #342)
- Fix the ordering of one-pass signatures (#302)
v0.5.2¶
Released: August 1, 2019
Bugs Fixed¶
- Signature subpackets of type 0 cause an infinite parse loop (#252)
v0.5.0¶
Released: August 1, 2019
New Features¶
- Add support for Curve25519
- Greatly improved Elliptic Curve Point format handling code (special thanks @rot42)
- Add support for IssuerFingerprint subpackets (thanks @J08nY)
- Add support for Key Revocation signatures
Bugs Fixed¶
- PGPy now correctly resynchronizes the block cipher stream when decrypting EncryptedDataPackets (the ones without MDC). (#160)
- PGPy now correctly defaults to SHA256 for keys that have no hash preferences set
Other Changes¶
- updated library dependencies and unit tests
v0.4.3¶
Released: August 16, 2017
v0.4.2¶
Released: August 9, 2017
New Features¶
- Packets with partial body lengths can now be parsed. For now, these packets are converted to have definite lengths instead. (#95) (#208)
Bugs Fixed¶
- Private key checksums are now calculated correctly (#172)
- PGPKey.decrypt was mistakenly using message.issuers instead of message.encrypters when determining whether or not the key was eligible to attempt decrypting the message (#183)
- Fixed an issue with parsing some cleartext messages (#184)
- Fixed signing already-encrypted messages (encrypt-then-sign) (#186) (#191)
- PGP*.from_blob now correctly raises an exception if given zero-length input (#199) (#200)
- Fixed an issue where PGPKey.decrypt would fail with an arcane traceback if the key is passphrase-protected and not unlocked. (#204)
v0.4.1¶
Released: April 13, 2017
Bugs Fixed¶
- Fixed an issue with dearmoring ASCII-armored PGP blocks with windows-style newlines (#156)
- Improved the robustness of the code that tunes the hash count for deriving symmetric encryption keys (#157)
- Fixed an issue with how public keys are created from private keys that was causing exports to become malformed (#168)
- Added explicit support for Python 3.6 (#166)
New Features¶
- Added support for Brainpool Standard curves for users who have OpenSSL 1.0.2 available
v0.4.0¶
Released: April 21, 2016
Bugs Fixed¶
- Armorable.from_blob was incorrectly not accepting bytes objects; this has been fixed (#140)
- Fixed an issue where string-formatting PGPUID objects would sometimes raise an exception (#142)
- Occasionally, the ASN.1 encoding of DSA signatures was being built in a way that although GPG could parse and verify them, it was incorrect, and PGPy incorrectly failed to verify them. (#143)
- Fixed an issue where keys with expiration dates set would have the wrong value returned from the
key.is_expired
property (#151)- Fixed an issue where PGPy would try to incorrectly coerce non-ASCII-compatible characters to ASCII-compatible bytes, potentially resulting in mojibake. (#154)
New Features¶
- ECDSA and ECDH keys can now be loaded (#109, #110)
- Keys can be generated with the following algorithms:
- RSA
- DSA
- ECDSA
- ECDH
- Keys can now be passphrase-protected. It is also possible to change the passphrase on a key that is already protected. (#149)
- ECDSA keys can now be used to sign and verify (#111)
- ECDH keys can now be used to encrypt and decrypt
- It is now possible to recover a public key from a private key (#92)
- Marker packets are now understood
Other Changes¶
- Removed support for Python 3.2, as multiple dependency libraries have already done so
- Added explicit support for Python 3.5
- Updated library dependencies where required or useful
- Reworked some IO-intensive routines to be less IO-intensive, and therefore faster
v0.3.0¶
Released: November 19, 2014
PGPy v0.3.0 is a major feature release.
Warning
The API changed significantly in this version. It is likely that anything using a previous version will need to be updated to work correctly with PGPy 0.3.0 or later.
Bugs Fixed¶
- When keys are exported, any certification signatures that are marked as being non-exportable are now skipped (#101)
- When the wrong key is used to validate a signature, the error message in the raised exception now makes that clear (#106)
New Features¶
- Standalone sigantures can now be generated
- Can now specify which User ID to use when signing things (#121)
- Can now create new User IDs and User Attributes (#118)
- Can now add new User IDs and User Attributes to keys (#119)
- Timestamp signatures can now be generated
- Can now sign keys, user ids, and user attributes (#104)
- Can now create new PGPMessages (#114)
- Key flags are now respected by PGPKey objects (#99)
- Multiple signatures can now be validated at once in cases where that makes sense, such as when validating self-signatures on keys/user ids (#120)
- Message signatures can now be verified (#117)
- Messages can now be encrypted/decrypted using a passphrase (#113)
- Cleartext messages can now be created and signed (#26)
- Cleartext messages with inline sigantures can now be verified (#27)
- Messages can now be loaded (#102)
- Messages can now be compressed (#100)
Other Changes¶
- CRC24 computation is now much faster than previous versions (#68)
- PGPKey and PGPKeyring APIs have changed significantly (#76)
- String2Key computation is now much faster than previous versions (#94)
- key material parts are now stored as integers (or
long
on Python 2.x) (#94)
v0.2.3¶
Released: July 31, 2014
PGPy v0.2.3 is a bugfix release
Bugs Fixed¶
- Fixed an issue where explicitly selecting a key and then trying to validate with it would erroneously raise an exception as though the wrong key were selected.
v0.2.2¶
Released: July 31, 2014
PGPy v0.2.2 is primarily a bugfix release.
Bugs Fixed¶
- Fixed a typo that would cause TypeError to be raised as bytecode was being generated (#85)
- Fixed an issue where unicode input on Python 2.7 could result in unexpected UnicodeDecodeError exceptions being raised
New Features¶
- Switched the main parse loop to use a bytearray instead of slicing a bytes, resulting in a ~160x speedup in parsing large blocks of pasing. (#87)
v0.2.1¶
Released: July 31, 2014
PGPy v0.2.1 is primarily a bugfix release.
Bugs Fixed¶
- Critical bit on signature subpackets was being ignored, and when set, causing a ValueError to be raised when trying to parse it. The critical bit is now being parsed and masked out correctly. (#81)
- No longer raises exceptions on unrecognized subpackets; instead, it now treats them as opaque.
- No longer raises exceptions on unrecognized packets; instead, it now treats them as opaque. This also applies to signature and key packets with versions other than v4.
- Fixed an issue where a User ID packet that lacked both a comment and an email address was failing to be found by the uid regex in KeyCollection.
- Fixed an issue where an old-format packet header with a length_type set longer than needed was resulting in the packet getting truncated.
- Fixed an issue where parsing a subpacket with a 2-byte length was erroneously being parsed as a 5-byte length.
- Fixed an issue where parsing a subpacket with a 5-byte length where the value was < 8434 was causing an error
- Fixed an issue where a packet or subpacket reporting a value marked reserved in RFC 4880 would cause ValueError to be raised during parsing.
- Key material marked as public key algorithm 20 (Reserved - Formerly ElGamal Encrypt or Sign) is now parsed as ElGamal key material.
- Fixed an issue where parsing a new-format packet header length where the first octet was 223 was erroneously reported as being malformed.
New Features¶
- Added support for parsing the ‘Preferred Key Server’ signature subpacket
- Added support for loading unsupported or unrecognized signature subpackets.
- Added support for loading unsupported or unrecognized packets.
v0.2.0¶
Released: July 20, 2014
Starting with v0.2.0, PGPy is now using the BSD 3-Clause license. v0.1.0 used the MIT license.
New Features¶
- Subkeys can now be accessed and used for actions supported by PGPKeyring (#67)
- DSA:
- Signing of binary documents now works (#16)
- Verification of signatures of binary documents now works (#15)
- Can now decrypt secret key material that was encrypted using:
- Camellia128 (#36)
- Camellia192 (#37)
- Camellia256 (#38)
- AES128 (#32)
- AES192 (#33)
- AES256 (#34)
- Blowfish (#31)
- Triple-DES (#30)
- IDEA (#29)
- PGP packets generated by PGPy now exclusively use new-style header lengths (#47)
- GPG Trust Packets are now understood and fully parsed (#14)
- Lots more packet types are now fully parsed
Known Issues¶
- Signing with 1024-bit DSA keys does not work with OpenSSL 0.9.8 (#48) - this primarily affects Mac OS X.
- Verifying signatures signed with any DSA key length other than 2048-bits does not work with OpenSSL 0.9.8 - this primarily affects Mac OS X.
Bugs Fixed¶
- PGP blocks loaded from ASCII armored blocks now retain their ASCII headers (#54)
- PGP new-style packet headers were not being properly parsed in all cases
- Many unit test enhancements
Installation¶
Platform Specific Notes¶
Windows¶
PGPy has not been formally tested on Windows. I see no reason why it wouldn’t work, but your mileage may vary. If you try it out and run into any issues, please submit bug reports on the issue tracker!
Linux¶
Gentoo¶
There are gentoo ebuilds available in the gentoo branch
RedHat/CentOS¶
Coming Soon!
Other Linux¶
Building PGPy on Linux requires a C compiler, headers for Python, headers for OpenSSL, and libffi, to support building Cryptography.
For Debian/Ubuntu, these requirements can be installed like so:
$ sudo apt install build-essential libssl-dev libffi-dev python-dev
For Alpine linux, the build requirements can be installed like so:
$ apk add build-base libressl-dev libffi-dev python-dev
You may need to install python3-dev
if you are using PGPy on Python 3.
For Fedora/RHEL derivatives, the build requirements can be installed like so:
$ sudo yum install gcc libffi-devel python-devel openssl-devel
Mac OS X¶
If you are on Mac OS, you may experience more limited functionality without installing a more capable version of OpenSSL.
You may refer to Cryptography’s documentation on Building cryptography on macOS for information on how to do so.
Installation¶
Once you have the prerequisites specified above, PGPy can be installed from PyPI using pip, like so:
$ pip install PGPy