How to Encrypt MQTT Payloads with Python – Example Code

mqtt-payload-encryption--smallEncrypting 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:

python-mqtt-payload-encrypt

Notes:

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.

mqtt-payload-encrption-script-output

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.

encrrypt-message-size

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.

run-python-shell

Enter the following commands shown n the screen shot to generate a key.

create-cipher-key

Now in both the subscribe and publish scripts replace the:

cipher_key = Fernet.generate_key()

with the key you created as shown below.

cipher-key

Was This Useful?

Python Scripts

You can download the actual script below.

Useful Resources:

Useful Tutorials and Resources:

Save

Save

Please rate? And use Comments to let me know more

12 comments

  1. 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).

    Regards,
    Sathish

    1. There is no requirement for client side certificates. Client side certificates are just a security option you can use username/passwords for authentication.
      Rgds
      Steve

  2. 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..

  3. 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.

    1. Hi
      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
      rgds
      steve

      1. 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.

        1. 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.
          Rgds
          Steve

          1. 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.
            Cheers!

  4. Hi Mr.Steve
    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 ?
    thank you

    1. Hi
      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

Leave a Reply

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