Publish and Subscribe to AES-256 Encrypted MQTT Messages to Node-RED from PHP Scripts

Various Node-Red crypto modules do not work with PHP, so to send an encrypted message from a PHP script (in this case from a Ubuntu server) to Node-RED we need our own code.

After a few hours of searching, testing various libs, more testing and debugging, I got this PHP to Node-RED code working today, and it works OK (serves its purpose):

I ended up modifying some well done StackOverflow code by inieto from here, Encrypt string in PHP and decrypt in Node.js to get both PHP and the JS to work together over MQTT:

Here is the PHP code:

<?php
/****************************************************
 *  EXAMPLE PHP SCRIPT TO SEND MQTT MESSAGE TO A
 *  NODE-RED FLOW USING AES-256 ENCRYPTION  v0.1
 *  Neo: www.unix.com   8 Feb 2020
 *  Public Domain.   Anyone Can Use As They Wish
 */
define(DEBUG, true);
define(AES_METHOD, "AES-256-CBC");
define(SHARED_SECRET, "My32charPasswordAndInitVectorStr");
date_default_timezone_set('UTC');
$thedate = date('l jS \of F Y h:i:s A');
$length = strlen($thedate);
if (DEBUG) {
    echo $thedate . "\n";
    echo $length . "\n";
}
$textToEncrypt = substr($thedate, 0, $length) . " is my AES-256 encrypted date.";
$iv = substr(SHARED_SECRET, 0, 16);

$encryptedMessage = openssl_encrypt($textToEncrypt, AES_METHOD, SHARED_SECRET, 0, $iv);
$command = '/usr/bin/mosquitto_pub -t debug/aes -m "' . $encryptedMessage . '" -q 1';

$output = shell_exec($command);
if (DEBUG) {
    $decryptedMessage = openssl_decrypt($encryptedMessage, AES_METHOD, SHARED_SECRET, 0, $iv);
    echo "$encryptedMessage\n";
    echo "$decryptedMessage\n";
}

The " crypto " lib is included in the current version of Node-RED, so they say, but it did not work for me until imported it into Node-RED as follows (maybe I did something wrong earlier when debugging):

ubuntu$cd ~/.node-red
ubuntu$ npm install crypto

But that is not enough, you need to edit / add to your settings.js file in your Node-RED base directory, like this:

 functionGlobalContext: {
        crypto:require("crypto")
    },

Then we can write a JS function node in Node-RED, as follows:

// Modified by Neo from original code by inieto 
// See reference above
// Public domain.  Please use as you might find useful:
// Node-RED method for requiring JS libs in functions
var crypto = global.get("crypto");
var encryptionMethod = "AES-256-CBC";
//shared secret must be 32 char length
var secret = "My32charPasswordAndInitVectorStr";
var iv = secret.substr(0, 16);

// Node-RED message payload is a JSON object
var encryptedMessage = msg.payload;

var decryptedMessage = decrypt(encryptedMessage, encryptionMethod, secret, iv);

// Node-RED message payload is a JSON object
var newMsg = { payload: decryptedMessage };
return newMsg;

// In this example, only the decrypt method is used in this setup
var decrypt = function(encryptedMessage, encryptionMethod, secret, iv) {
  var decryptor = crypto.createDecipheriv(encryptionMethod, secret, iv);
  return (
    decryptor.update(encryptedMessage, "base64", "utf8") +
    decryptor.final("utf8")
  );
};

// The following encrypt method it not used in this example, but it is included
// here for completeness (from the original post)
var encrypt = function(plain_text, encryptionMethod, secret, iv) {
  var encryptor = crypto.createCipheriv(encryptionMethod, secret, iv);
  return (
    encryptor.update(plain_text, "utf8", "base64") + encryptor.final("base64")
  );
};

My debugging layout looks like this in Node-RED:

Node-RED Debug Console Results:

2/8/2020, 4:55:22 PMnode: c399ebfe.d90398
debug/aes : msg.payload : string[108]
"Al1mNY9VSEaOy85SdrmOW0vApe2ABeOcjW6eQeRXaEOCtJxULBvW/e6Jyr9K2p1+0mqf40xTQZri9uf18nHQFn92anuMA8zi5ipunp72U9Y="
2/8/2020, 4:55:22 PMnode: bd20fdce.5bfef
msg.payload : string[71]
"Saturday 8th of February 2020 09:55:21 AM is my AES-256 encrypted date."
2/8/2020, 4:56:02 PMnode: c399ebfe.d90398
debug/aes : msg.payload : string[108]
"Al1mNY9VSEaOy85SdrmOW0vApe2ABeOcjW6eQeRXaEMAHwwHRrVVgVmIy/Xd7A9fc7jkxkk8P8p3aaNgAoEIyL+goIjS6dMLAhdhT+1uB1E="
2/8/2020, 4:56:02 PMnode: bd20fdce.5bfef
msg.payload : string[71]
"Saturday 8th of February 2020 09:56:01 AM is my AES-256 encrypted date."
2/8/2020, 4:57:01 PMnode: c399ebfe.d90398
debug/aes : msg.payload : string[108]
"Al1mNY9VSEaOy85SdrmOW0vApe2ABeOcjW6eQeRXaEPVMwgS2G/DZq/AqM4RDyUCJ+pNqTxnCzXe0BtIyAsf21L+mSp2uHW8icxPG4t++aw="
2/8/2020, 4:57:02 PMnode: bd20fdce.5bfef
msg.payload : string[71]
"Saturday 8th of February 2020 09:57:01 AM is my AES-256 encrypted date."
2/8/2020, 4:58:01 PMnode: c399ebfe.d90398
debug/aes : msg.payload : string[108]
"Al1mNY9VSEaOy85SdrmOW0vApe2ABeOcjW6eQeRXaEPrRIilm8M/nB7G8KsqoRP4qDi743QNN4cxlmvEjtEV4zW4NUDhndBIHI1xcyW+ui0="
2/8/2020, 4:58:02 PMnode: bd20fdce.5bfef
msg.payload : string[71]
"Saturday 8th of February 2020 09:58:01 AM is my AES-256 encrypted date."

With this example PHP and Node-JS JS function code, we can publish (encrypting on the PHP side) and subscribe (decrypting on the Node-RED side) any Linux server data we wish to Node-RED using PHP, securely with AES-256 encryption.

1 Like