|Date:||October 14, 2010|
The gnupg module allows Python programs to make use of the functionality provided by the GNU Privacy Guard (abbreviated GPG or GnuPG). Using this module, Python programs can encrypt and decrypt data, digitally sign documents and verify digital signatures, manage (generate, list and delete) encryption keys, using proven Public Key Infrastructure (PKI) encryption technology based on OpenPGP.
This module is expected to be used with Python versions >= 2.4, as it makes use of the subprocess module which appeared in that version of Python. Development and testing has been carried out on Windows (Python 2.4, 2.5, 2.6, 3.1, Jython 2.5.1) and Ubuntu (Python 2.4, 2.5, 2.6, 3.0, 3.1, Jython 2.5.1).
Apart from a recent-enough version of Python, in order to use this module you need to have access to a compatible version of the GnuPG executable. The system has been tested with GnuPG v1.4.9 on Windows and Ubuntu. On a Linux platform, this will typically be installed via your distribution’s package manager (e.g. apt-get on Debian/Ubuntu).
Note: On Windows, it is not necessary to perform a full installation of GnuPG, using the standard installer, on each computer: it is normally sufficient to distribute only the executable, gpg.exe, and a DLL which it depends on, iconv.dll. These files do not need to be placed in system directories, nor are registry changes needed. The files need to be placed in a location such that implicit invocation will find them - such as the working directory of the application which uses the gnupg module, or on the system path if that is appropriate for your requirements. Alternatively, you can specify the full path to the gpg executable.
This module is based on an earlier version, GPG.py, written by Andrew Kuchling. This was further improved by Richard Jones, and then even further by Steve Traugott. The gnupg module is derived from Steve Traugott’s module, and uses Python’s subprocess module to communicate with the GnuPG executable, which it uses to spawn a subprocess to do the real work.
GnuPG works on the basis of a “home directory” which is used to store public and private keyring files as well as a trust database. You need to identify in advance which directory on the end-user system will be used as the home directory, as you will need to pass this information to gnupg.
You interface to the GnuPG functionality through an instance of the GPG class:
>>> gpg = gnupg.GPG(gnupghome='/path/to/home/directory')
If the home directory does not exist, it will be created (including any missing parent directories). Thereafter, all the operations available are accessed via methods of this instance. If the gnupghome parameter is omitted, GnuPG will use whatever directory is the default (consult the GnuPG documentation for more information on what this might be).
The GPG() constructor also accepts the following additional optional keyword arguments:
If the gpgbinary executable cannot be found, a ValueError is raised in GPG.__init__().
The module provides functionality for generating (creating) keys, listing keys, deleting keys, and importing and exporting keys.
The first thing you typically want to do when starting with a PKI framework is to generate some keys. You can do this as follows:
>>> key = gpg.gen_key(input_data)
where input_data is a special command string which tells GnuPG the parameters you want to use when creating the key. To make life easier, a helper method is provided which takes keyword arguments which allow you to specify individual parameters of the key, as in the following example:
>>> input_data = gpg.gen_key_input(key_type="RSA", key_length=1024)
Sensible defaults are provided for parameters which you don’t specify, as shown in the following table:
|Parameter||Keyword Argument||Default value||Example values||Meaning of parameter|
|Key-Type||key_type||“RSA”||“RSA”, “DSA”||The type of the primary key to generate. It must be capable of signing.|
|Key-Length||key_length||1024||1024, 2048||The length of the primary key in bits.|
|Name-Real||name_real||“Autogenerated Key”||“Fred Bloggs”||The real name of the user identity which is represented by the key.|
|Name-Comment||name_comment||“Generated by gnupg.py”||“A test user”||A comment to attach to the user id.|
|Name-Email||name_email||<username>@<hostname>||“firstname.lastname@example.org“||An email address for the user.|
If you don’t specify any parameters, the values in the table above will be used with the defaults indicated. There is a whole set of other parameters you can specify; see this GnuPG document for more details. While use of RSA keys is common (they can be used for both signing and encryption), another popular option is to use a DSA primary key (for signing) together with a secondary El-Gamal key (for encryption). For this latter option, you could supply the following additional parameters:
|Parameter||Keyword Argument||Example values||Meaning of parameter|
|Subkey-Type||subkey_type||“RSA”, “ELG-E”||The type of the secondary key to generate.|
|Subkey-Length||subkey_length||1024, 2048||The length of the secondary key in bits.|
|Expire-Date||expire_date||“2009-12-31”, “365d”, “3m”, “6w”, “5y”, “seconds=<epoch>”, 0||The expiration date for the primary and any secondary key. You can specify an ISO date, A number of days/weeks/months/years, an epoch value, or 0 for a non-expiring key.|
|Passphrase||passphrase||“secret”||The passphrase to use. If this parameter is not specified, no passphrase is needed to access the key.|
Whatever keyword arguments you pass to gen_key_input() will be converted to the parameters expected by GnuPG by replacing underscores with hyphens and title-casing the result. You can of course construct the parameters in your own dictionary params and then pass it as follows:
>>> input_data = gpg.gen_key_input(**params)
Key generation requires the system to work with a source of random numbers. Systems which are better at generating random numbers than others are said to have higher entropy. This is typically obtained from the system hardware; the GnuPG documentation recommends that keys be generated only on a local machine (i.e. not one being accessed across a network), and that keyboard, mouse and disk activity be maximised during key generation to increase the entropy of the system.
Unfortunately, there are some scenarios - for example, on virtual machines which don’t have real hardware - where insufficient entropy causes key generation to be extremely slow. If you come across this problem, you should investigate means of increasing the system entropy. On virtualised Linux systems, this can often be achieved by installing the rng-tools package. This is available at least on RPM-based and APT-based systems (Red Hat/Fedora, Debian, Ubuntu and derivative distributions).
To export keys, use the export_keys() method:
>>> ascii_armored_public_keys = gpg.export_keys(keyids) # same as gpg.export_keys(keyids, False) >>> ascii_armored_private_keys = gpg.export_keys(keyids, True) # True => private keys
For the keyids parameter, you can use a sequence of anything which GnuPG itself accepts to identify a key - for example, the keyid or the fingerprint could be used. If you want to pass a single keyid, then you can just pass in a string which identifies the key.
To import keys, get the key data as an ASCII string, say key_data. Then:
>>> import_result = gpg.import_key(key_data)
This will import all the keys in key_data. The number of keys imported will be available in import_result.count and the fingerprints of the imported keys will be in import_result.fingerprints.
Now that we’ve seen how to generate, import and export keys, let’s move on to finding which keys we have in our keyrings. This is fairly straightforward:
>>> public_keys = gpg.list_keys() # same as gpg.list_keys(False) >>> private_keys = gpg.list_keys(True) # True => private keys
The returned value from list_keys() is a subclass of Python’s list class. Each entry represents one key and is a Python dictionary which contains useful information about the corresponding key.
To delete keys, their key identifiers must be specified. If a public/private keypair has been created, a private key needs to be deleted before the public key can be deleted:
>>> key = gpg.gen_key(gpg.gen_key_input()) >>> fp = key.fingerprint >>> str(gpg.delete_keys(fp)) # same as gpg.delete_keys(fp, False) 'Must delete secret key first' >>> str(gpg.delete_keys(fp, True))# True => private keys 'ok' >>> str(gpg.delete_keys(fp)) 'ok' >>> str(gpg.delete_keys("nosuchkey")) 'No such key'
The argument you pass to delete_keys() can be either a single key identifier (e.g. keyid or fingerprint) or a sequence of key identifiers.
Data intended for some particular recipients is encrypted with the public keys of those recipients. Each recipient can decrypt the encrypted data using the corresponding private key.
To encrypt a message, use the following approach:
>>> encrypted_ascii_data = gpg.encrypt(data, recipients)
If you want to encrypt data in a file (or file-like object), use:
>>> encrypted_ascii_data = gpg.encrypt_file(stream, recipients) # e.g. after stream = open(filename, "rb")
In both cases, recipients is a list of key fingerprints for those recipients. For your convenience, if there is a single recipient, you can pass the fingerprint rather than a 1-element array containing the fingerprint. Both methods accept the following optional keyword arguments:
The encrypt_file method takes the following additional keyword arguments:
To decrypt a message, use the following approach:
>>> decrypted_data = gpg.decrypt(data)
If you want to decrypt data in a file (or file-like object), use:
>>> decrypted_data = gpg.decrypt_file(stream) # e.g. after stream = open(filename, "rb")
Both methods accept the following optional keyword arguments:
The decrypt_file method takes the following additional keyword argument:
Data intended for digital signing is signed with the private key of the signer. Each recipient can verify the signed data using the corresponding public key.
To sign a message, do the following:
>>> signed_data = gpg.sign(message)
or, for data in a file (or file-like object), you can do:
>>> signed_data = gpg.sign_file(stream) # e.g. after stream = open(filename, "rb")
These methods both return an object such that str(signed_data) gives the signed data in a non-binary format. They accept the following optional keyword arguments:
Note: If the data being signed is binary, calling str(signed_data) may raise exceptions. In that case, use the fact that signed_data.data holds the binary signed data. Usually the signature itself is ASCII; it’s the message itself which may cause the exceptions to be raised. (Unless a detached signature is requested, the result of signing is the message with the signature appended.)
The detach keyword argument was added in version 0.2.5.
To verify some data which you’ve received, do the following:
>>> verified = gpg.verify(data)
To verify data in a file (or file-like object), use:
>>> verified = gpg.verify_file(stream) # e.g. after stream = open(filename, "rb")
You can use the returned value in a Boolean context:
>>> if not verified: raise ValueError("Signature could not be verified!")
If you want to verify a detached signature, use the following approach:
>>> verified = gpg.verify_file(stream, path_to_data_file)
The second argument to verify_file (data_filename) was added in version 0.2.5.
The module makes use of the facilities provided by Python’s logging package. A single logger is created with the module’s __name__, hence gnupg unless you rename the module. A NullHandler instance is added to this logger, so if you don’t use logging in your application which uses this module, you shouldn’t see any logging messages. If you do use logging in your application, just configure it in the normal way.
The distribution includes a test harness, test_gnupg.py, which contains unit tests (with integrated doctests) covering the functionality described above. You can invoke test_gnupg.py with one or more optional command-line arguments. If no arguments are provided, all tests are run. If arguments are provided, they collectively determine which of the tests will be run:
The gnupg module, being based on proven earlier versions, is quite usable. However, there are many features of GnuPG which this module does not take advantage of, or provide access to. How this module evolves will be determined by feedback from the user community.
If you find bugs and want to raise issues, please do so via the Google Code project.
All feedback will be gratefully received; please send it to the discussion group.