doc: python bindings howto

* Replaced the single encryption methods with one main way (i.e. cut
  the low level stuff involving SEEK_SET instructions).
This commit is contained in:
Ben McGinnes 2018-03-19 10:00:44 +11:00
parent 4811ff7b6c
commit 64c5886132

View File

@ -436,6 +436,7 @@
section we will look at how to programmatically encrypt data,
decrypt it, sign it and verify signatures.
** Encryption
:PROPERTIES:
:CUSTOM_ID: howto-basic-encryption
@ -446,85 +447,35 @@
the second example the message will be encrypted to multiple
recipients.
*** Encrypting to one key
:PROPERTIES:
:CUSTOM_ID: howto-basic-encryption-single
:END:
The text is then encapsulated in a GPGME Data object as =plain= and
the =cipher= object is created with another Data object. Then we
create the Context as =c= and set it to use the ASCII armoured
OpenPGP format. In later examples there will be alternative
methods of setting the OpenPGP output to be ASCII armoured.
Once the the Context is set the main issues with encrypting data
is essentially reduced to key selection and the keyword arguments
specified in the =gpg.Context().encrypt()= method.
Next we prepare a keylist object in our Context and follow it with
specifying the recipients as =r=. Note that the configuration in
one's =gpg.conf= file is honoured, so if you have the options set
to encrypt to one key or to a default key, that will be included
with this operation.
This is followed by a quick check to be sure that the recipient is
actually selected and that the key is available. Assuming it is,
the encryption can proceed, but if not a message will print stating
the key was not found.
The encryption operation is invoked within the Context with the
=c.op_encrypt= function, loading the recipients (=r=), the message
(=plain=) and the =cipher=. The =cipher.seek= uses =os.SEEK_SET=
to set the data to the correct byte format for GPGME to use it.
At this point we no longer need the plaintext material, so we
delete both the =text= and the =plain= objects. Then we write the
encrypted data out to a file, =secret_plans.txt.asc=.
#+begin_src python
import gpg
import os
rkey = "0x12345678DEADBEEF"
text = """
Some plain text to test with. Obtained from any input source Python can read.
It makes no difference whether it is string or bytes, but the bindings always
produce byte output data. Which is useful to know when writing out either the
encrypted or decrypted results.
"""
plain = gpg.core.Data(text)
cipher = gpg.core.Data()
c = gpg.core.Context()
c.set_armor(1)
c.op_keylist_start(rkey, 0)
r = c.op_keylist_next()
if r == None:
print("""The key for user "{0}" was not found""".format(rkey))
else:
try:
c.op_encrypt([r], 1, plain, cipher)
cipher.seek(0, os.SEEK_SET)
with open("secret_plans.txt.asc", "wb") as afile:
afile.write(cipher.read())
except gpg.errors.GPGMEError as ex:
print(ex.getstring())
#+end_src
*** Encrypting to one key using the second method
:PROPERTIES:
:CUSTOM_ID: howto-basic-encryption-monogamous
:END:
This example re-creates the first encryption example except it
uses the same =encrypt= method used in the subsequent examples
instead of the =op_encrypt= method. This means that, unlike the
=op_encrypt= method, it /must/ use byte literal input data.
Those keyword arguments are: =recipients=, a list of keys
encrypted to (covered in greater detail in the following section);
=sign=, whether or not to sign the plaintext data, see subsequent
sections on signing and verifying signatures below (defaults to
=True=); =sink=, to write results or partial results to a secure
sink instead of returning it (defaults to =None=); =passphrase=,
only used when utilising symmetric encryption (defaults to
=None=); =always_trust=, used to override the trust model settings
for recipient keys (defaults to =False=); =add_encrypt_to=,
utilises any preconfigured =encrypt-to= or =default-key= settings
in the user's =gpg.conf= file (defaults to =False=); =prepare=,
prepare for encryption (defaults to =False=); =expect_sign=,
prepare for signing (defaults to =False=); =compress=, compresses
the plaintext prior to encryption (defaults to =True=).
#+begin_src python
import gpg
rkey = "0x12345678DEADBEEF"
a_key = "0x12345678DEADBEEF"
text = b"""Some text to test with.
Since the text in this case must be bytes, it is most likely that
@ -534,56 +485,51 @@
"""
c = gpg.Context(armor=True)
rpattern = list(c.keylist(pattern=rkey, secret=False))
logrus = []
for i in range(len(rpattern)):
if rpattern[i].can_encrypt == 1:
logrus.append(rpattern[i])
cipher = c.encrypt(text, recipients=logrus, sign=False, always_trust=True)
rkey = list(c.keylist(pattern=a_key, secret=False))
ciphertext, result, sign_result = c.encrypt(text, recipients=rkey, sign=False)
with open("secret_plans.txt.asc", "wb") as afile:
afile.write(cipher[0])
afile.write(ciphertext)
#+end_src
With one or two exceptions, this method will probably prove to be
easier to implement than the first method and thus it is the
recommended encryption method. Though it is even more likely to
be used like this:
Though this is even more likely to be used like this; with the
plaintext input read from a file, the recipient keys used for
encryption regardless of key trust status and the encrypted output
also encrypted to any preconfigured keys set in the =gpg.conf=
file:
#+begin_src python
import gpg
rkey = "0x12345678DEADBEEF"
a_key = "0x12345678DEADBEEF"
afile = open("secret_plans.txt", "rb")
with open("secret_plans.txt", "rb") as afile:
text = afile.read()
afile.close()
c = gpg.Context(armor=True)
rpattern = list(c.keylist(pattern=rkey, secret=False))
logrus = []
for i in range(len(rpattern)):
if rpattern[i].can_encrypt == 1:
logrus.append(rpattern[i])
cipher = c.encrypt(text, recipients=logrus, sign=False, always_trust=True)
rkey = list(c.keylist(pattern=a_key, secret=False))
ciphertext, result, sign_result = c.encrypt(text, recipients=rkey,
sign=True, always_trust=True,
add_encrypt_to=True)
with open("secret_plans.txt.asc", "wb") as afile:
afile.write(cipher[0])
afile.write(ciphertext)
#+end_src
If the =recipients= paramater is empty then the plaintext is
encrypted symmetrically. If no =passphrase= is supplied as a
parameter or via a callback registered with the =Context()= then
an out-of-band prompt for the passphrase via pinentry will be
invoked.
*** Encrypting to multiple keys
:PROPERTIES:
:CUSTOM_ID: howto-basic-encryption-multiple
:END:
Encrypting to multiple keys, in addition to a default key or a key
configured to always encrypt to, is a little different and uses a
slightly different call to the =op_encrypt= call demonstrated in the
previous section.
Encrypting to multiple keys essentially just expands upon the key
selection process and the recipients from the previous examples.
The following example encrypts a message (=text=) to everyone with
an email address on the =gnupg.org= domain,[fn:3] but does /not/ encrypt
@ -711,7 +657,8 @@
:CUSTOM_ID: howto-basic-signing
:END:
The following sections demonstrate how to specify
The following sections demonstrate how to specify keys to sign with.
*** Signing key selection
:PROPERTIES:
@ -743,6 +690,7 @@
bytes or None and not a list. A string with two fingerprints
won't match any single key.
*** Normal or default signing messages or files
:PROPERTIES:
:CUSTOM_ID: howto-basic-signing-normal
@ -798,6 +746,7 @@
afile.write(signed[0])
#+end_src
*** Detached signing messages and files
:PROPERTIES:
:CUSTOM_ID: howto-basic-signing-detached
@ -840,6 +789,7 @@
afile.write(signed[0])
#+end_src
*** Clearsigning messages or text
:PROPERTIES:
:CUSTOM_ID: howto-basic-signing-clear
@ -1307,6 +1257,7 @@
:CUSTOM_ID: cheats-and-hacks
:END:
** Group lines
:PROPERTIES:
:CUSTOM_ID: group-lines
@ -1357,6 +1308,7 @@
:CUSTOM_ID: copyright-and-license
:END:
** Copyright (C) The GnuPG Project, 2018
:PROPERTIES:
:CUSTOM_ID: copyright
@ -1364,6 +1316,7 @@
Copyright © The GnuPG Project, 2018.
** License GPL compatible
:PROPERTIES:
:CUSTOM_ID: license