The faint smile on your face turns into an expression of panic the moment you check your e-mail. “Oh, my God! The CEO has just forwarded an e-mail to Kiran, a union leader, instead of Kiran, the CFO.” But you manage to save the day. The recipient is on leave, and you delete the mail from his inward queue.
Your HR chief asks you to check your e-mail. When you do so, you can’t help but smile. The CEO has just declared a holiday for his birthday! But the smile doesn’t last long. The HR chief asks you to find out who sent that e-mail, as it surely wasn’t the CEO. You are reminded of the line routinely printed by banks on their statements: “This is a computer-generated statement and does not require a signature!”
Increasingly, your financial dealings are online. The statements are being sent by e-mail. To minimise the chances of the wrong person viewing confidential information, the statements are password protected. However, the passwords aren’t very strong. They protect against casual snooping, which is fine for most of us. But you do need to put some effort into figuring out the password for each statement. It’s not easy for you and your colleagues to do so.
There has to be a better way to manage all these scenarios.
Public key infrastructure
Public key-based algorithms have been around for about as long as I have been in the software field. Ubuntu owes its existence to the money made from the sale of Thawte, which issues digital certificates.
PGP (Pretty Good Privacy) came into existence in the early 1990s and GPG (GNU Privacy Guard) that conformed to the OpenPGP standard was available by the end of the 90s.
I have used a public key only to start an SSH session on a remote computer without having to give a password. But I have relied on GPG whenever I installed packages from a Fedora repository. Keeping the private key safe is a critical part of these security processes. The fear that the signing key may have been compromised resulted in the closure of the Fedora repositories for a noticeable period of time.
One reason for the lack of applications using OpenPGP may be that it is hard to get started with them. It is important to realise that this technique is based on people trusting each other and not on a third-party certificate. Would I trust the keys more if the issuing company had been audited by, say, PWC? A transaction between two parties does not need a certificate from a third party.
Before getting into programming using GPG, let us consider the steps involved in using the public key infrastructure with an e-mail client, Evolution. We choose Evolution as it comes with GPG support. Many e-mail clients now support OpenPGP — for example, Sylpheed. Thunderbird requires the Enigmail plug-in, which, unfortunately, was not compatible with the x64 application I was using. The default security mechanism of Thunderbird is S/MIME. Visit this forum topic for more details.
GPG and e-mail
The first step is to create your own pair of keys for your e-mail account, [email protected] It is simple. Just give the following command:
You will be asked a few questions and if in doubt, just use the defaults. It is better if you give a passphrase to protect your private key, especially if others may have access to the system you are using.
You will need to send your public key to your collaborators. So, export it as a text file and e-mail it:
gpg -a --export [email protected] > my_public_key.asc
Your friends can call you to verify that the fingerprint of the key is valid. You can find out the fingerprint by the following command:
You can now sign and send an e-mail to your friends. In Evolution, choose the option ‘Security’ on the menu bar. Select the ‘PGP Sign’ check box.
When you get the public key from your friends and collaborators, you will need to import it. This step is also simple:
gpg --import his_public_key.asc
GPG expects each key to be signed by a trusted entity before it is regarded as valid. So, you will need to sign the key you have just imported as follows—assuming that your friend’s e-mail address is [email protected]:
gpg --sign-key [email protected]
Now, you can encrypt the e-mail you are sending to your friend. When composing an e-mail, choose the ‘Security’ option from the menu bar and select the ‘PGP Encrypt’ check box. You can encrypt and sign the e-mail by selecting both the sign and the encrypt check boxes.
If you have received an encrypted and signed e-mail from your friend, Evolution will display it as usual, except that there will be a message at the bottom of the e-mail informing you that it had a valid signature and was encrypted.
If you forward the encrypted mail to someone else, including your friend, the recipient will not be able to decode the mail. This is very useful when sending e-mails to a relation who loves to gossip and has an uncontrollable mailing list! A side effect is that unless you copy an encrypted mail to yourself, you can’t see what you sent.
If you do not have the public key of a recipient and you give the request to encrypt the mail, Evolution will give you an error. However, if both the Kirans—the union leader and the CFO in our opening paragraph—had a public key in the key ring, encryption is not going to prevent you from making a mistake.
An example of an application
Programs can make mistakes—and they do so consistently. They do not normally make silly mistakes unless, of course, programmed to do so.
Suppose you want to send salary slips to all your employees, and want each employee to view only his or her salary details. Every employee, on joining, can create a key pair and register the individual public key with the company. The admin staff need not manage these keys securely! In fact, they can freely distribute the public key to anyone who needs it — for example, the bank where a salary account is opened.
Python has a module called
pygpgme, which is a wrapper for the
gpgme, GPG Made Easy, library. It is installed on Fedora, as
yum needs it. It lacks one small thing—documentation!
gpgme library is documented, but seems to lack any tutorials or articles on how to get started with it.
The solution in such cases is to download the source. You can actually ignore the source code and search for the test cases. That can act as an excellent starting point.
Encrypting/decrypting a file
For your application, you need to be able to encrypt a file. So, try the following code:
import gpgme infile = open(‘salary_slip.txt’) outfile = open(‘salary_slip.asc’,’w’) ctx = gpgme.Context() ctx.armor = True recipient_key = ctx.get_key([email protected]) ctx.encrypt_sign([recipient_key], gpgme.ENCRYPT_ALWAYS_TRUST, infile, outfile) outfile.close() infile.close()
The code is pretty straightforward. Open the two files and obtain the GPG context. The ‘armor’ option creates an ASCII file rather than a binary one. Obtain the key by using the recipient’s e-mail address, then encrypt and sign the file by passing a list of the keys. The second option informs you that the keys should be trusted. You will be prompted for the passphrase while signing in, if you have specified one while creating your key.
The code for decrypting a file is even simpler:
import gpgme infile = open(‘salary_slip2.asc’) outfile = open(‘salary_slip.out’,’w’) ctx = gpgme.Context() sigs = ctx.decrypt_verify(infile, outfile) outfile.close() infile.close()
gpgme will raise an exception in case decryption fails or the signature is not valid. The ‘decrypt and verify’ method will return a list of signatures. You may want to get some more information about the signatures.
Since there is only one key in your case, try the following code:
signing_key = ctx.get_key(sigs.fpr) print signing_key.uids.name print signing_key.uids.email
You get the key by using the fingerprint and then print the information you may need.
Let’s suppose you just wanted to sign a text:
import gpgme infile = open(‘salary_slip.txt’) outfile = open(‘salary_slip_signed.asc’,’w’) ctx = gpgme.Context() ctx.armor = True ctx.sign(infile, outfile, gpgme.SIG_MODE_CLEAR) outfile.close() infile.close()
You have chosen the clear sign mode so that the text is readable and the signature identifiable.
This will be enough for the moment. You can read the code in the tests subdirectory of the pygpgme source to learn more.
Mime and PGP
You are now in a position to combine encryption with the e-mail module so that the hard part is done by the application, and the user can access secure information very conveniently. The format for a Mime-encrypted message is described in www.ietf.org/rfc/rfc3156.txt.
Start with the various modules that need to be imported:
import smtplib import gpgme from email import encoders from email.mime.base import MIMEBase from email.mime.multipart import MIMEMultipart from StringIO import StringIO
StringIO is a file-like class for manipulating a string buffer. It is, essentially, a memory file.
You will need to create a multi-part Mime formatted message with the attachment you wish to e-mail (see docs.python.org/library/email-examples.html for more details). Assume that you are attaching a PDF file:
def create_message(filename): outer = MIMEMultipart() fp = open(filename, ‘rb’) msg = MIMEBase(‘application’, ‘pdf’) msg.set_payload(fp.read()) fp.close() encoders.encode_base64(msg) msg.add_header(‘Content-Disposition’, ‘attachment’, filename=filename) outer.attach(msg) return outer.as_string()
You will next encrypt the message:
def encrypt_payload(in_msg, out_msg): ctx = gpgme.Context() ctx.armor = True recipient_key = ctx.get_key([email protected]) ctx.encrypt([recipient_key], gpgme.ENCRYPT_ALWAYS_TRUST, in_msg, out_msg)
Now, you will need to create another multi-part Mime message that has the encrypted content as the payload. The Mime body must consist of exactly two parts, the first with the content type “application/pgp-encrypted”. This part contains the control information. The second part contains the encrypted content as an octet-stream.
def mime_pgp_message(fp): outer = MIMEMultipart(_subtype=’encrypted’,protocol=’application/pgp-encrypted’) outer['Subject'] = 'Attached Encrypted - 5' outer['To'] = [email protected]' outer['From'] = [email protected]' msg = MIMEBase('application', 'pgp-encrypted') outer.attach(msg) enc_part = MIMEBase('application','octet-stream', name='encrypted.asc') fp.seek(0) enc_part.set_payload(fp.read()) outer.attach(enc_part) return outer.as_string()
Now, you are ready to send the message:
def send_message(sender, recipients, composed): s = smtplib.SMTP() s.connect() s.sendmail(sender, recipients, composed) s.close()
You would be calling the above routines as follows:
in_msg = StringIO(create_message(‘Open.pdf’)) out_msg = StringIO() encrypt_payload(in_msg, out_msg) composed = mime_pgp_message(out_msg) send_message([email protected], [[email protected]], composed)
Unfortunately, signing the document introduces one more level of complexity. Before encrypting the message, you would need to sign it. For this, too, a multi-part message with two parts in the body, is required. So, the steps would be:
- Create the Mime message
- PGP Sign the Mime message
- Create a multi-part Mime message with protocol application/pgp-signature
- PGP encrypt the signed Mime message
- Create a multi-part Mime message with protocol application/pgp-encrypted
- Send the message
This article turned o ut to be much harder to write than I expected, as I could not find any tutorials or simple documentation on using gpgme or Mime/PGP-encrypted, whether for Python or any other language. In case anyone knows of any, I would love to hear about it.
It is a pity that banks force us to change our passwords every few months. We also need to ensure that our passwords are not the same at all sites. Nor the same as the ones used on the previous few occasions. In short, keeping track of passwords is one horrendous problem. Desktop tools that help use the appropriate password for each application or website are a solution for this problem.
A public key environment would, unambiguously, shift the task of preventing any leakage of passwords from the host sites to the user only. The critical advantage is that we need to protect only one private password. Last but not least, it will save us from making hundreds of enemies because we used our Gmail password at a social networking site, involuntarily inflicting our friends with the “I want to be your friend” spam.