Encrypting the MQTT payload rather than the link has the advantage that the data is encrypted end to end and not just between the broker and the client.
It also means that the intermediate brokers don’t need to support SSL and that you don’t need to obtain and install certificates.
It is therefore much easier to set up and use.
As a demonstration I’ve modified the simple pub-sub script to use payload encryption.
Here is a screen shot of the script with annotations:
Note 1 -I’ve used the cryptography package to do the encryption. See this article for an example usage and the cryptography web page here.
Note 2– First we create an encryption key – cipher_key = Fernet.generate_key(). This key is used to encrypt and decrypt and we would need to use this same key on the receiving client. In our example the sender and receiver are the same client.
Note 3-The message to be encrypted must be in bytes.
Note 4: We need to create a UTF-8 encoded string to pass as the message payload to the MQTT publish method.
Note 5– The received message is already in bytes and so we pass it straight to the decrypt function.
Note 6: We then convert the decrypted byte message to a UTF-8 string as normal.
Running the Script
When we run the script this is what we see.
By enabling client logging as follows:
def on_log(client, userdata, level, buf): print("log: ",buf) client.on_log=on_log
You can look at the message size.
You will notice that the outgoing message size is much larger when it has been encrypted.
In the example the 2 byte “on” message becomes 100 bytes when encrypted.
Using Separate Clients
If you have two separate clients a publisher and subscriber then you will need to generate the key manually, and paste it into the code on both the subscribing client and publishing client.
Open a python command prompt which you can do from the IDE.
Enter the following commands shown n the screen shot to generate a key.
Now in both the subscribe and publish scripts replace the:
cipher_key = Fernet.generate_key()
with the key you created as shown below.
You can download the actual script below.
- Fernet System for symmetric encryption
- Tutorials point- Encryption with Python
- Python 3: An introduction to encryption
- Encryption Basic principles
- Learning about cryptography
- Introduction to MQTT Security Mechanisms
Useful Tutorials and Resources:
- Introduction to MQTT Security Mechanisms
- The Paho MQTT Python Client-Beginners Guide
- Logging Sensor Data to a SQL Database Using Python
- Logging sensor Data to a file Using Python
- Sending JSON Data over MQTT with Python
- Checking Active MQTT Client Connections
- Simple Controllable MQTT Sensor Simulator in Python
- Sending a File Over MQTT Using Python
- Republish HTML Data Over MQTT
Hello Mr. Steve
We have a scenario where there are many clients (readers). Therefore, having a client side certificate would not be feasible (especially when the client side certificate expires – how do we update 100s of readers etc).
Is it possible to just have server side certificate and not have client side certificate (like how we work with browsers and accessing an https site).
There is no requirement for client side certificates. Client side certificates are just a security option you can use username/passwords for authentication.
Hi steve… Thank you for the great information… I’m trying to run the code.. but I’m receiving error as invalid syntax, perhaps you forgot comma… I dont understand this.. Could you please advise. Thank you..
what version of python are you using. Which script are you using the combined or the individual?
Doesn’t work for some reason. I tried running all the three scripts following the instructions. But I am not being able to receive or decrypt the message. It just gets stuck in the CONNECT AND CONACK loop forever.
It looks like it can’t connect to the broker. Check the broker IP address and port in the script and also that you broker is running
Okay, will check this and get back.
So I worked it out. But the script requires some changes without which the on_message callback never gets called.
In the python script:
1) client=paho.client(“client-001”) needs to be changed to
client= paho.Client(“”, True, None, paho.MQTTv31) for each client object
This was after a bit of debugging with trial-error, seems the python client uses the older MQTT version for some reason.
2) The port number wasn’t in the publish-subsribe-encrypt-payload.py. So I added that because I needed it for client.connect(broker,port) usage.
3) While publishing, the message to be sent is the encrypted_message generated.
It worked for me after making these three changes. I used the HiveMQ WebSocket client for the connection.
Tks for the feedback. You are correct is was written over a year ago using an older MQTT client version. I’ll update it with your feedback.
No problem, actually this page helped me out a lot while working on a college report related to
‘Security in IoT’
Thanks for your help 🙂
Let me know if you need the updated script, I had modified it for the same machine client scenario.
You have my email, I presume.
i’ve written a simple code for payload encryption, i’v done it with AES-128 CBC mode ,it works fine ,
the senario is very simple : the publisher send a JSON payload format that include the encryption key , IV (Initialisation Vector) and the encrypted data, the subscriber extract the key and IV then decrypt the data received, but i want to do a sort of hybrid encryption ,to encrypt the key with Asymetric algorithm, i know the famous RSA, but after reading somre articles, RSA is not suitable for constrained ressources, have you any idea wich algorithm can i use or somthing else that ensure the key trasmition ?
Sorry but I chose the simpler solution of using a fixed pre-shared key. I took the view that anything more complicated and it would be easier to use SSL and certificates