Xor encryption Arduino code To Node Red?

Hi All,
I am still looking for encryption of my data transmitted in 433MHZ .I am not looking for absolute security but just a tip so that my messages are not read and decrypted easily.
I found an XOR encryption that looks very easy to use, and ARDUINO can do it easily.

Now I want NODE RED to do it so that ARDUINO and RASPBERRY can communicate.

This is the ARDUINO code :

void setup() {
  Serial.begin (9600);

  char texte[] = "Ceci est une phrase lambda a coder";
  int taille = strlen(texte);

Serial.println("1. Cryptage:");
  codage_xor(texte, taille, "superclef"); //=> ALLER a la fct
  Serial.println(texte);

  Serial.println("wait...");
  delay(2000);
  
Serial.println("2. Decryptage:");
  Serial.println(codage_xor(texte, taille, "superclef"));
}  // FIN DE SETUP

void loop() {
}//FIN de loop

//========================================================================
char * codage_xor(char * texte, int taille, char * cle) {
  int c_cle = 0;
  for (int c_txt = 0; c_txt < taille; c_txt++) { // pour toute la chaine
    texte[c_txt] ^= cle[c_cle++];        // XOR du car. avec un car. de la clé
    if (!cle[c_cle]) {                   // si on est au bout de la clé
      c_cle = 0;                       // on boucle
    }
  }
  return texte;
} // FIN de fonction

This is the same in NODE RED flow :

  var message =  "Ceci est une phrase lambda a coder";
  var length = message.length;
  var password= "superclef"; //

  function codage_xor( texte,  taille,  cle) {
    var c_cle = 0;
    for (var c_txt = 0; c_txt < taille; c_txt++) { // pour toute la chaine
      texte[c_txt] ^= cle[c_cle++];        // XOR du car. avec un car. de la clé
      if (!cle[c_cle]) {                   // si on est au bout de la clé
        c_cle = 0;                       // on boucle
      }
    }
    return texte;
}

var texte = codage_xor(message,  length,  password);
    
    msg.payload = texte;
    return msg;

The message isn't crypted in the debug payload :

msg.payload : string[34]
"Ceci est une phrase lambda a coder"

Does someone help me to found my error in the Flow ?

Thanks
Christian

I don't understand, where is the debug node?

This is how the loop will iterate over the message and the password:

In the very first iteration the code will do a bitwise XOR on "C" and "s". The problem is that the bitwise will not work on characters. In JavaScript this will always return number zero.

In order to do a XOR you need to convert the character to a number.

Possibly what you want is the character code in the code set UTF, in which case you need to use the JavaScript function: String.charCodeAt()

The expression will look like: texte.charCodeAt(c_txt) ^ cle.charCodeAt(c_cle)

Likewise, you may want to convert number to character codes, in which case you will resort to the JavaScript function: String.fromCharCode()

What is the "encrypted " phrase you got in the arduino code for the text and password you provided ?

I have written here what is in my Function node. The debug node is after this function flow.

This is the complet Flow :

[{"id":"805c94b2.540f78","type":"function","z":"fe2c7bc6.bd49c8","name":"xor","func":"  var message =  \"Ceci est une phrase lambda a coder\";\n  var length = message.length;\n  var password= \"superclef\"; //\n\n  function codage_xor( texte,  taille,  cle) {\n\n    var c_cle = 0;\n\n    for (var c_txt = 0; c_txt < taille; c_txt++) { // pour toute la chaine\n      texte[c_txt] ^= cle[c_cle++];        // XOR du car. avec un car. de la clé\n      if (!cle[c_cle]) {                   // si on est au bout de la clé\n        c_cle = 0;                       // on boucle\n      }\n    }\n    return texte;\n}\n\nvar texte = codage_xor(message,  length,  password);\n    msg.warn(texte);\n    msg.payload = texte;\n    return msg;\n    \n////////////////////////////////////////////////////////////////////////////////////////\n    /*\n\nvoid setup() {\n  Serial.begin (9600);\n\n  char texte[] = \"Ceci est une phrase lambda a coder\";\n  int taille = strlen(texte);\n\nSerial.println(\"1. Cryptage:\");\n  codage_xor(texte, taille, \"superclef\"); //=> ALLER a la fct\n  Serial.println(texte);\n\n  Serial.println(\"wait...\");\n  delay(2000);\n  \nSerial.println(\"2. Decryptage:\");\n  Serial.println(codage_xor(texte, taille, \"superclef\"));\n}  // FIN DE SETUP\n\n//===================================\n//=              LOOP               =\n//===================================\nvoid loop() {\n}//FIN de loop\n\n//=================================================================================\n//======================    AUTRES FONCTIONS     ==================================\n//================================================================================\nchar * codage_xor(char * texte, int taille, char * cle) {\n  int c_cle = 0;\n  for (int c_txt = 0; c_txt < taille; c_txt++) { // pour toute la chaine\n    texte[c_txt] ^= cle[c_cle++];        // XOR du car. avec un car. de la clé\n    if (!cle[c_cle]) {                   // si on est au bout de la clé\n      c_cle = 0;                       // on boucle\n    }\n  }\n  return texte;\n} // FIN de fonction\n////////////////////////////////////////////////////////////////////////////////////////\n// the result : \n//1. Cryptage: 0\u0010\u0013\fR\u0006\u001f\u0011F\u0006\u001b\u0015E\u0002\u000b\u001e\u0004\u0015\u0016U\u001c\u0004\u001f\u0001\b\u0004F\u0012U\u0013\n//\u0016\u0006\u001e\n//wait...\n//2. Decryptage: Ceci est une phrase lambda a coder\n\n    */","outputs":1,"noerr":0,"x":272.8571472167969,"y":3633,"wires":[["483b0ffe.af29d"]]},{"id":"c5b6dc8f.131fe","type":"inject","z":"fe2c7bc6.bd49c8","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":"","x":115.00000381469727,"y":3632.8571128845215,"wires":[["805c94b2.540f78"]]},{"id":"483b0ffe.af29d","type":"debug","z":"fe2c7bc6.bd49c8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":430.71435165405273,"y":3631.999981880188,"wires":[]}]

the result in ARDUINO is :
image

As expected you will get non printable characters in the resulting string (encrypted message) since result of the XOR between two number can result in any binary number. It means you will may have troubles if you try to compare encrypted strings.

Anyways here is how I think your Node-RED flow will appear after modified.

[{"id":"2104be11.87c342","type":"tab","label":"Flow 10","disabled":false,"info":""},{"id":"f936e0ff.424","type":"inject","z":"2104be11.87c342","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":120,"wires":[["131e4397.45c46c"]]},{"id":"131e4397.45c46c","type":"function","z":"2104be11.87c342","name":"XOR Encrypt","func":"  var message =  \"Ceci est une phrase lambda a coder\";\n  var length = message.length;\n  var password= \"superclef\"; //\n\n  function codage_xor( texte,  taille,  cle) {\n    var c_cle = 0;\n    var result = [];\n    for (var c_txt = 0; c_txt < taille; c_txt++) { // pour toute la chaine\n      result[c_txt] = (texte.charCodeAt(c_txt) ^ cle.charCodeAt(c_cle)) ;        // XOR du car. avec un car. de la clé\n      //node.warn(result[c_txt]);\n      c_cle++;\n      \n      if (!cle[c_cle]) {                   // si on est au bout de la clé\n        c_cle = 0;                       // on boucle\n      }\n    }\n    return result;\n}\n\nvar texte = codage_xor(message,  length,  password);\n    \n    //msg.payload = texte;\n    msg.payload = String.fromCharCode(...texte);\n    return msg;\n    \n    ","outputs":1,"noerr":0,"x":310,"y":120,"wires":[["c1ef0a57.cdc948"]]},{"id":"c1ef0a57.cdc948","type":"debug","z":"2104be11.87c342","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":490,"y":120,"wires":[]}]

You may want to compare the arduino encryption with the JavaScript. In such case it is better to use the array of "xored' values instead of the string format. You can do this change in the function node by doing this change:

    msg.payload = texte;
    //msg.payload = String.fromCharCode(...texte);

instead of

    //msg.payload = texte;
    msg.payload = String.fromCharCode(...texte);

YES !!! that's sound good :

image
image

Let's try to transmit encrypted message from ARDUINO to NODE RED ..... wait and see ...

1 Like

@Andrei
here are the rest of my tests:
Arduino transmit encrypted message


=> NodeRed to decrypt:
nodeRed%20received%20and%20decrypt
the problem is that during encryption, as you said, there are non-printable characters like here: a "carriage return" that we see in Arduino and Node Red. But who disturbs the decryption!

Do you have an idea to generate an encrypted message that is readable on both sides?

(I tried AES, XXTEA ... without success.) The only one I managed to make work together is https://flows.nodered.org/node/node-red-node-base64 with the Arduino library #include <Base64. h> but there is no securit key :roll_eyes:

Indeed, it would not work due to encoding issues. You already found a good solution: base64 encoding.

If you can do it in Arduino side then voila ! It is very easy to encode your string to base64 in Node-RED.

We will add these two lines to your function node:

let cryptdata =  Buffer.from(texte);
msg.payload = cryptdata.toString('base64');

Flow:

[{"id":"5607422e.0d149c","type":"tab","label":"Flow 11","disabled":false,"info":""},{"id":"f100f447.4d4058","type":"inject","z":"5607422e.0d149c","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":100,"wires":[["1993e37e.0e796d"]]},{"id":"1993e37e.0e796d","type":"function","z":"5607422e.0d149c","name":"XOR Encrypt Base64","func":"  var message =  \"Ceci est une phrase lambda a coder\";\n  var length = message.length;\n  var password= \"superclef\"; //\n\n  function codage_xor( texte,  taille,  cle) {\n    var c_cle = 0;\n    var result = [];\n    for (var c_txt = 0; c_txt < taille; c_txt++) { // pour toute la chaine\n      result[c_txt] = (texte.charCodeAt(c_txt) ^ cle.charCodeAt(c_cle)) ;        // XOR du car. avec un car. de la clé\n      //node.warn(result[c_txt]);\n      c_cle++;\n      \n      if (!cle[c_cle]) {                   // si on est au bout de la clé\n        c_cle = 0;                       // on boucle\n      }\n    }\n    return result;\n}\n\nvar texte = codage_xor(message,  length,  password);\n    \n//msg.payload = texte;\n//msg.payload = String.fromCharCode(...texte);\n//node.warn(texte);\nlet cryptdata =  Buffer.from(texte);\nmsg.payload = cryptdata.toString('base64');\n\n\n    return msg;\n    \n    ","outputs":1,"noerr":0,"x":380,"y":100,"wires":[["dc1a2469.367408"]]},{"id":"dc1a2469.367408","type":"debug","z":"5607422e.0d149c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":610,"y":100,"wires":[]}]

Ths is how your message will looks like after encrypted with the given password:

s-02

Note that in this case we first encrypt the message with your method and only then we encode the partial result to base64.

As you can see the string will be longer, which is not bad as it is a kind of obfuscation that helps your purpose.

Great, thanks to this better and better,

how to do the opposite to decrypt : first the base64, then the xor encoding?

Exactly, in order to decrypt you will first load the message into a buffer. Node.JS provides an easy way to decode de base64 into a buffer.

let msgbuffer = new Buffer(msg.payload, 'base64');

Once the data is in the buffer you will run the xor algorithm for each element of the buffer. In the end, you will need to convert the data back to string format.

I did an experiment a couple of hours ago to refactor the code using ES6 syntax as well as to use Buffers as much as possible. This last part is unfinished as the code still uses an intermediate array to store data.

My personal preference when decoding, parsing, etc is always use buffers instead of arrays.

Unfinished flow to encrypt and decrypt (but it works):

[{"id":"5607422e.0d149c","type":"tab","label":"Flow 11","disabled":false,"info":""},{"id":"9b587fc4.26aac","type":"inject","z":"5607422e.0d149c","name":"Inject message","topic":"","payload":"Ceci est une phrase lambda a coder","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":220,"wires":[["33bd1ba4.2f39f4"]]},{"id":"33bd1ba4.2f39f4","type":"function","z":"5607422e.0d149c","name":"Refactored encryption","func":"let message =  msg.payload;\nlet password = \"superclef\"; \n\nlet mes = Buffer.from(message);\nlet paw = Buffer.from(password);\nlet pawIndex = paw.lenght;\n\nlet res = [];\nfor (let c of mes) {\n    res.push(c ^ nextpaw());\n}\n\nfunction nextpaw()\n{\n    return paw[pawIndex++] || (pawIndex=0, paw[pawIndex++]); \n}\n\nlet cryptdata =  Buffer.from(res);\nlet base64cryptdata = cryptdata.toString('base64');\nmsg.payload = base64cryptdata;\nreturn msg;","outputs":1,"noerr":0,"x":380,"y":220,"wires":[["d13daef3.e0002","256619d9.b0e556"]]},{"id":"d13daef3.e0002","type":"debug","z":"5607422e.0d149c","name":"Encrypted base64","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":630,"y":220,"wires":[]},{"id":"256619d9.b0e556","type":"function","z":"5607422e.0d149c","name":"Refactored decryption","func":"let password = \"superclef\"; \nlet mes = new Buffer(msg.payload, 'base64');\n\nlet paw = Buffer.from(password);\nlet pawIndex = paw.lenght;\n\nlet res = [];\nfor (let c of mes) {\n    res.push(c ^ nextpaw());\n}\n\nfunction nextpaw()\n{\n    return paw[pawIndex++] || (pawIndex=0, paw[pawIndex++]); \n}\n\nlet decryptdata =  Buffer.from(res);\nmsg.payload = decryptdata.toString('utf8');\nreturn msg;","outputs":1,"noerr":0,"x":460,"y":300,"wires":[["82d0b1b3.00839"]]},{"id":"82d0b1b3.00839","type":"debug","z":"5607422e.0d149c","name":"Decrypted","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":670,"y":300,"wires":[]},{"id":"ef6f42d8.3f7d7","type":"inject","z":"5607422e.0d149c","name":"Inject message","topic":"","payload":"Ca n’a rien à voir avec la choucroute","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":260,"wires":[["33bd1ba4.2f39f4"]]},{"id":"bd42eccf.39cd4","type":"inject","z":"5607422e.0d149c","name":"Inject message","topic":"","payload":"Ah, la vache!","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":300,"wires":[["33bd1ba4.2f39f4"]]}]
1 Like

Andrei you speak so nice French ! Where did you learn speak like this ? :rofl:

I had a lot of fun managing, for nearly 20 years, telecom projects for a major French retailer... learned plenty of dirty French words.... :joy:

1 Like

i'm sure you 're also best in dirty French words than in software development lol

Mais , revenons Ă  nos moutons :ram: :wink:

As I said, the goal is to communicate ARDUINO <=> NodeRed with encrypted messages (xor + base64). I would use JSON like this:
The ARDUINO remote control asks RPI
{" From ":" telecChri "," to ":" rpi "," message ":" openGarage "," value ":" null "}
RPI will respond to ARDUINO:
{" from ":" rpi "," to ":" telecChri "," message ":" thisIsTheTime "," value ":" 1557435438 "}
ARDUINO confirm the code to RPI:
{" From ":" telecChri "," to ":" rpi "," message ":" theTimeIs "," value ":" 1557435438 "}
RPI receives the "security code" (which is the UNIX time at the moment of the request: there is no 2 identical times !) and will open the garage.
It is a kind of "security code rotating - encrypted" . It couldn't be reproduced, and there, I think we can not have better security to open his portal lol :v:

i could use this "protocol" for my other sensor like :
{" From ":" meteo"," to ":" rpi "," message ":" theExtTempIs "," value ":" 23.6"}
{"From":"alarm"," to ":" rpi "," message ":" theGarageIsOpen"," value ":"null"} etc ...

What do you think about ?

It sounds nice. You are adding a new security layer by using this protocol. Probably it won´t protect you from jam and replay attack (RollJam) but let´s face it, when it comes to RF it is hard to design absolute security.

Hi Andrei,
It may be off topic but regarding the ARDUINO part, do you think I should use the ArduinoJson.h library or make myself my payload with Serial.print like "{\"from\":\"telecChri\",\"to\" ...

If you agre we could talk in MP, in French :slight_smile: ?

I am totally in. When your project is working fine I will consider adding this functionality to my only finished Arduino project that is an electronic security dog that barks like a mad beast. In the worst case, if someone breaks the security, the worst that can happen is the dog scaring people around. Today it is activated by RF (433 Mhz) or by a PIR sensor. It will be great to add remote control via MQTT. Ah, and even funnier when I replace the 5 Watts speakers by 100 Watts speakers. Waiting your PM. À bientôt !