Wednesday, October 2, 2013

Python-gnupg on a Raspberry Pi

Installing Python-gnupg (http://pythonhosted.org/python-gnupg/) on a Raspberry Pi shouldn't be much different than installing it on any other *nix system.  I'm documenting it here just for my own personal notes.

Install gnupg
This goes pretty much like you'd expect:

sudo apt-get install gnupg

Install Python-gnupg
First we need pip (and setup_tools, ...):
sudo apt-get install python-dev
wget https://bitbucket.org/pypa/setuptools/raw/0.8/ez_setup.py -O - | sudo python
curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
sudo python get-pip.py

Now we can get gnupg:
sudo pip install python-gnupg

Basics
The following script creates a key using gnupg and installs that key in ~/.gnupg:
import gnupg

gpg = gnupg.GPG()

# generate a key
# first we need the input data
# really we shouldn't use key lengths shorter than 2048
input_data = gpg.gen_key_input(key_type="RSA", 
                               key_length=2048,
                               name_real="Tom",
                               name_comment="Test key",
                               name_email="tom@inyourbits.com")
key = gpg.gen_key(input_data)
print key.fingerprint

Not Fast Enough
The script above works (and doesn't do much), but takes a long time to run.

pi@3-14159 ~/gnupgTesting $ time python gpgtest.py 

real 6m4.396s
user 0m6.270s
sys 0m0.140s

This can be sped up by install rng-tools, however rng-tools requires a hardware random number source.

The Raspberry Pi has a hardware component for random number generation, but the software for it was just recently released.  (http://scruss.com/blog/2013/06/07/well-that-was-unexpected-the-raspberry-pis-hardware-random-number-generator/).

You may need to completely update your Pi (see the instructions in the link above), but I was able to get away with just this (and adding bcm2708-rng to /etc/modules):
sudo modprobe bcm2708-rng
sudo apt-get install rng-tools

Now performance is much better.

pi@3-14159 ~/gnupgTesting $ time python gpgtest.py 

real 0m5.524s
user 0m4.070s
sys 0m1.060s

Encrypting Data
In this example, 'bob@inyourbits.com' is the intended recipient (we've previously imported Bob's key) and "hello world" is the data we're going to encrypt.


>>> import gnupg
>>> gpg = gnupg.GPG()
>>> encrypted_data = gpg.encrypt("hello world", "bob@inyourbits.com")
>>> print encrypted_data
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.12 (GNU/Linux)

hQEMA4/T/riECknHAQf/cZWpMb4T4hwADtY+gS+0H0yKyKeq7hR6VFb2GGsGoRwW
uGiw63grv1HTMr5tiiOGtZgR3BvVsHJkgU6aeIwe3oqNlrQv2kEgu4IDe8vYNgqA
1M4KuNfFPvpk0wPrOFgmUIf5wxJwKGvo9gWR89pnti1zpAwPWFEplm/cRcEf3XQV
KmsiVCSdY22/14gv2XRh5wM/gzpjwI96RsmBPmSFZvkpBl8h9W5IZsq87oOmxg60
yLIkf1R9wm+EDukjAuhMQ+C0i/+ThiHp87I8LZD7kmzMot19+q4xiA5geetAgcwh
pDUCFwCjYSHVIf2Q//epRtEHfYCSQaJTO+WQcIaDCdJGAWQkJsdoDnlTMDYCwIth
cPLOMf1eWJGBThLwPOl1Rji9GqO0GX7dyvGDWTv89GvWD69phMyn+UAo5pOCtD/d
OBPVk+WSlg==
=sTPy
-----END PGP MESSAGE-----

Decrypting Data
Here we decrypt the data sent to Bob (we must have Bob's private key installed for this to work).  Note the use of str() around 'encrypted_data'. That's because .encrypt doesn't return a string, but rather something that can be turned in to a string.

>>> decrypted_data = gpg.decrypt(str(encrypted_data))
>>> print decrypted_data
hello world

Pesky Details
In this example I had the private keys for both parties installed on my system. That's not realistic, but it's enough to become familiar with the software before starting to much around across systems.  Key distribution is often hard.  Regular gpg can be used to do the key management if you don't need to do it in python. It's probably easier that way.