Send encrypted messages using Azure Service bus and GnuPG using Python

You will learn to:
– create key-pairs.
– encrypt and decrypt strings in python.
– send and receive encrypted messages with Azure Service Bus with python.

 

The Internet of Things is going to grow much much bigger than the Internet of humans very soon. Some machines already talk to each other using different communication protocols. Tesla automobiles update their firmware just like your smart phone does. Homes can lock doors, turn on/off lights remotely, etc. More and more devices are getting connected to the Cloud and this is great.

But, what if someone tells your house to lock you in and turn off the heater in the middle of the winter? How would the house know that someone other than you is controlling it?
Maybe you are on vacation and you tell the house to enter into “sleep” mode. Someone could read this and realise that nobody’s home…

Secure communication protocols for the internet of things are not utilised that often!

This tutorial gives an example of how to communicate a message from A to B with a basic level of protection. This is not a tutorial for high end cryptography and it shouldn’t be used for 007 missions.

>>> Get started: Encryption

To hide the content of a message or a file you can encrypt it. You need a key to decrypt the message, a key only you keep.

There are many encryption options that you can find. In this case we are going to use GnuPG, it is open source and free. They recommend simple software to handle keys and perform basic en/de-cryption of files:
For Windows
For Mac

There are different types of encryption, in this example we will use something called public key encryption. It means that you need two keys, one for the public and one only for yourself. The public key acts as an open safe, where anyone can input data and lock it (encrypt). Then they can send the encrypted data freely and only you know the combination (private key) to decrypt the data.

>>> Creating keys is the first step. In this case we will create a key-pair using a tool rather than using the python libraries, if you already have keys, jump to the next section.

>>> Create a key in Windows using gpg4win.

image

Click on File>New Certificate…
Choose to create an OpenPGP key pair.
Enter a name and an email, the comment is optional.

image

You will be asked for a password.

Once you have created your private key it is time to get the public key out of it.
File>Export Certificates… and save it with a simpler name such as bob.asc
You can share this public key and and even upload it to public servers.

>>> Create a key pair on a Mac.

Install the GPG Suite …
Open GPG Keychain Access.
image

Click in New and type a name, email and password:

image

You have now a new pair of private and public keys, lets export the public key to share with the world.
Click export and save it with your name.

 

>>> Encrypt data using Python

Now that you have your private and public key it is time to encrypt a message.
Since the idea behind the internet of things is to have an embedded computer such as a Raspberry Pi or BeagleBone to send and/or receive the messages and make it easy, we will use python on Linux.

Make sure you have downloaded and installed Python in your system.

Install the required libraries to use GnuPG for python.
Another option is here.
Windows installer here.

For installation in Mac, open Terminal and type (in bash):

sudo pip install python-gnupg

Once installed we can add the library to our python script in parts:
(The entire code can also be found below)

import gnupg
gpg = gnupg.GPG()
from pprint import pprint

I also added pprint which helps to visualize data easier, this is optional. More about pprint module.

Next, tell the computer where your keys are:

gpg = gnupg.GPG(gnupghome='/Users/Bob/GPG/keys/')

Choose your own path, I recommend to create your own folder and export your keys in a separate private and public folder, keep them safe.

Now import your keys by uncommenting (removing the  ‘ ‘ ‘  at the top and bottom of each section):

#import
'''
print '------------import------------'
key_data = open('/Users/Bob/GPG/keys/private/alice_roberts.asc').read()
print key_data
import_result = gpg.import_keys(key_data)
pprint(import_result.results)
'''

Make sure to import the public key of your recipient but also your private key to be able to decrypt incoming messages, so run this for each key at least once.
To encrypt a string:

#encrypt string

unencrypted_string = 'Hello, secret friend!'
encrypted_data = gpg.encrypt(unencrypted_string, 'alice@roberts.com', always_trust = True)
encrypted_string = str(encrypted_data)
print 'encrypt ok: ', encrypted_data.ok
print 'status: ', encrypted_data.status
print 'stderr: ', encrypted_data.stderr
print 'unencrypted_string: ', unencrypted_string
print 'encrypted_string: ', encrypted_string

In this example the recipient is the key I just created (alice@roberts.com), but you can put here the recipients email or name. I set the option always_trust = True because I know that the creator of the key is legit and not fake, make sure you validate this too.

You will see the encrypted message:

—–BEGIN PGP MESSAGE—–
Version: GnuPG/MacGPG2 v2.0.22 (Darwin)

hQEMA5mEYC+z/ZjmAQgAs+Pa4LtmVBa1RwStActD8N11nKNvLM7jwG/wE9iLOOxk
rp/6LYKqKDf/zz20dUc7NmlgQnNhHd7iPiXX0XarztJGoUu9jqeSIy1t76F8DeIm
/2E4DvD/V8sUHJGH7UFOL84eiAjbobweGWYgu3ajrUMzERJUN8o8yN+H02UQGnq+
/BI1uHzEqCvZiOIju6J53PdyCqZzOco2WgOXqvFxDE67dqRRtvB5tUV39iw1L986
AblG2GrgE75W2voCZzH0ii1fCZ3MXd1iNECbnFMyeNXeC/J8jz9qqCmvsoSUEKfh
PlI6yj6JCApILieMOs1Jb4a4FWVK6IFVZ9PNzMYr59JCAWW0jyK2KVrekDeGwal8
D9+IxcdqMb2TB7PKgPCRJ3BQ4bNMq2BA86ww4Y5X6tZCxsmfA4QBUU6ZdOY21eUO
LM3y
=PxFU
—–END PGP MESSAGE—–

We know it actually says: ‘ Hello, secret friend! ’ but nobody else in the world does.

To decrypt the message use:

#decrypt 
string decrypted_data = gpg.decrypt(encrypted_string, passphrase='password') 
print 'ok: ', decrypted_data.ok 
print 'status: ', decrypted_data.status 
print 'stderr: ', decrypted_data.stderr 
print 'decrypted string: ', decrypted_data.data

 

Replace the password with your own. You will see the result:

ok:  True
status:  decryption ok
stderr:  [GNUPG:] ENC_TO 9984602FB3FD98E6 1 0
[GNUPG:] USERID_HINT 9984602FB3FD98E6 alice roberts <alice@roberts.com>
[GNUPG:] NEED_PASSPHRASE 9984602FB3FD98E6 08C2B4985C75852E 1 0
[GNUPG:] GOOD_PASSPHRASE
gpg: encrypted with 2048-bit RSA key, ID B3FD98E6, created 2014-09-09
“alice roberts <alice@roberts.com>”
[GNUPG:] BEGIN_DECRYPTION
[GNUPG:] DECRYPTION_INFO 2 9
[GNUPG:] PLAINTEXT 62 1410391068
[GNUPG:] PLAINTEXT_LENGTH 21
[GNUPG:] DECRYPTION_OKAY
[GNUPG:] GOODMDC
[GNUPG:] END_DECRYPTION

decrypted string:  Hello, secret friend!

Process finished with exit code 0

Thats it!
You have created a key, imported it, encrypted and decrypted a message!

Here is the code as a whole:

import gnupg
gpg = gnupg.GPG()
from pprint import pprint
    #create path to store keys
gpg = gnupg.GPG(gnupghome='/Users/Bob/GPG/keys/')

#import
'''
print '------------import------------'
key_data = open('/Users/Bob/GPG/keys/public/alice_roberts.asc').read()
print key_data
import_result = gpg.import_keys(key_data)
pprint(import_result.results)
'''

#list keys
'''
print '-----------list----------'
gpg = gnupg.GPG(gnupghome='/Users/Bob/GPG/keys/')
public_keys = gpg.list_keys()
private_keys = gpg.list_keys(True)
print 'public keys:'
pprint(public_keys)
print 'private keys:'
pprint(private_keys)
'''

#encrypt string
'''
unencrypted_string = 'Hello, secret friend!'
encrypted_data = gpg.encrypt(unencrypted_string, 'alice@roberts.com', always_trust = True)
encrypted_string = str(encrypted_data)
print 'encrypt ok: ', encrypted_data.ok
print 'status: ', encrypted_data.status
print 'stderr: ', encrypted_data.stderr
print 'unencrypted_string: ', unencrypted_string
print 'encrypted_string: ', encrypted_string
'''

#decrypt string
'''
decrypted_data = gpg.decrypt(encrypted_string, passphrase='password')
print 'ok: ', decrypted_data.ok
print 'status: ', decrypted_data.status
print 'stderr: ', decrypted_data.stderr
print 'decrypted string: ', decrypted_data.data
'''

Uncomment the required parts.

>>> Sending encrypted messages through Azure Service Bus.

Once you have successfully created the tools to encrypt and decrypt messages in python we can simply add the required lines of code to send the encrypted messages through the Cloud to anywhere you want.

Azure Service Bus is a Microsoft service that lets you send information contained in messages no larger than 64kB (Iver 64k is possible but it counts as multiple messages!), you can send millions if you want either in a queue format or a subscription. To learn more about Azure Service bus click here.

If you want to know in higher detail how to send a message to the Service Bus, check my previous tutorial (here and here)

First:
Install the service bus for Python and the SDK.
In case you want to download more stuff, go here.

Second:
Follow this instructions to set up an Azure account.
You will learn about how to set up an account and then a queue, read it through to get the idea.

The following is the code as a whole, I will explain each part below:

from azure.servicebus import * 
import gnupg 
#gpg = gnupg.GPG() 
from pprint import pprint 
#create path to store keys 
gpg = gnupg.GPG(gnupghome='/Users/Bob/GPG/keys') 
#import key ''' 
key_data = open('/Users/Bob/GPG/keys/public/alice_roberts.asc').read() 
print key_data 
import_result = gpg.import_keys(key_data) 
pprint(import_result.results) 
''' 
bus_service = ServiceBusService(service_namespace='sensornetwork', account_key='s8S0GXhTNLOHrfsEdww/QE0+UYZIVxss8TK7CQkg29Y=', issuer='owner') 
queuename = 'taskqueue' 
#bus_service.create_queue(queuename) 
#uncomment to create a queue, only once #encrypt unencrypted_string = "End of SB Session" 
encrypted_data = gpg.encrypt(unencrypted_string, 'alice@roberts.com', always_trust = True) 
encrypted_string = str(encrypted_data) 
print 'successful encryption: ', encrypted_data.ok

 

#send through service bus 
encrypted_msg = Message(encrypted_string) 
bus_service.send_queue_message(queuename, encrypted_msg) 
print 'Message sent to the queue:', queuename print 'Body:' , encrypted_string 
#receive messages 
while True: 
   #msg = bus_service.read_delete_queue_message('taskqueue') 
   msg = bus_service.receive_queue_message ('taskqueue') 
   #peek_lock=True print 'Body: ',(msg.body) 
   decrypted_data = gpg.decrypt(msg.body, passphrase='password') 
   print 'successful decryption: ', decrypted_data.ok 
   print 'Message Content: ', decrypted_data.data msg.delete() 
   if (decrypted_data.data == 'End of SB Session'): 
      print 'Received message: "End of SB Session"' 
      break print 'python script finished.'

First you import both libraries, one for the Service Bus, and the other for the GnuPG.

After importing the keys you find the service bus settings. This is where you must add your own namespace, account_key (not related with the encryption), and issuer.
Create a queue to target your messages. You can have many different queues or topics for different themes. If you want to have specific topics that specific recipients should read, then don’t use queues and check out Service Bus Topics and Subscriptions.

The encryption is the same as before.

Then we send the encrypted string via the Service bus to our queue, make sure you create one queue first.
The encrypted message gets added into a Message which is sent to the cloud and stored in the cloud until you retrieve it.

To receive the message I created a “while True”, this will then run until a break is sent.
The code will fetch messages, decrypt them, print them, delete them and check if they match a specific string that I called ‘End of SB Session’.

To read the message only once, you can remove msg.delete(), otherwise the messages will stray in the cloud, you need to manage this.

Congratulations, you can now send and receive encrypted messages through the cloud. Add some sensors and report the data confidentially. Take a look at the Geiger Counter example,

by Martin Garcia (plusmartin.com) & Steven Johnston

Leave a Reply

Your email address will not be published. Required fields are marked *