CryptoJS encode displays different results despite same input

Hey all,
I've been using the CryptoJS library to encode a string to authenticate a user with another program. The way it works is that you send an auth request, and you get two strings. Then you combine and encode those strings with your password to generate your auth key.

You get: a salt and a challenge string.

  • Concatenate password + salt, generate a SHA256 hash then encode the result to base64.
  • Take the result of the first step and concatenate it with the challenge string.
  • Take the new string you created in the second step, generate a SHA256 hash and then encode the result to base64. And there's your auth key.

It's a bit confusing, more info is available at https://github.com/Palakis/obs-websocket/blob/4.x-current/docs/generated/protocol.md.

The problem I've been having is that despite the same salt and challenge strings, I get different results if I assign the strings to a variable vs when I manually put them in an inject node. I've tried assigning the strings to a message, to a flow variable and a global variable, and each time I get a different result despite the same strings every time. The two strings change whenever the program is relaunched, so they need to be read from the payload and can't be manually entered. My flow is below.
Thanks!

[{"id":"755f0b8.5893ff4","type":"inject","z":"59ca3f9a.a4f18","name":"Manual Entry","props":[{"p":"password","v":"password","vt":"str"},{"p":"salt","v":"aszng9OoS6ybw9yTW2WR4GySMNdM3srSQ4KE70aungY=","vt":"str"},{"p":"challenge","v":"KSO+hOFs1q5SkEnx8bvp67Om2zyHDD6ZJF4NHAa3R94=","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":160,"y":100,"wires":[["786daa7f.3fe284"]]},{"id":"36ed9ba2.56be04","type":"inject","z":"59ca3f9a.a4f18","name":"Variable","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"authRequired\": true,     \"challenge\": \"KSO+hOFs1q5SkEnx8bvp67Om2zyHDD6ZJF4NHAa3R94=\",     \"message-id\": \"f8100636.83edd8\",     \"salt\": \"aszng9OoS6ybw9yTW2WR4GySMNdM3srSQ4KE70aungY=\",     \"status\": \"ok\" }","payloadType":"json","x":130,"y":140,"wires":[["b699085c.1bbdd8"]]},{"id":"786daa7f.3fe284","type":"function","z":"59ca3f9a.a4f18","name":"Auth Function","func":"var CryptoJS = context.global.cryptojs;\n\nvar secret_hash = CryptoJS.SHA256(msg.password + msg.salt);\nvar secret = CryptoJS.enc.Base64.stringify(secret_hash);\n\nvar auth_response_hash = CryptoJS.SHA256(secret + msg.challenge);\nvar auth_response = CryptoJS.enc.Base64.stringify(auth_response_hash);\n\nmsg.payload = auth_response;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":540,"y":120,"wires":[["b958d436.f24a48"]]},{"id":"b958d436.f24a48","type":"debug","z":"59ca3f9a.a4f18","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":730,"y":120,"wires":[]},{"id":"b699085c.1bbdd8","type":"change","z":"59ca3f9a.a4f18","name":"Assign Variables","rules":[{"t":"set","p":"password","pt":"msg","to":"password","tot":"str"},{"t":"set","p":"salt","pt":"msg","to":"payload.salt","tot":"str"},{"t":"set","p":"challenge","pt":"msg","to":"payload.challenge","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":140,"wires":[["786daa7f.3fe284"]]}]

put a debug node (set to display the Complete msg object) on the output of the 'Manual Entry' inject and the 'Assign Variables' change nodes and look at the results. Are they the same?

Since I played around with CryptoJS two years ago, I thought I might have a go at your question.

The answer has nothing to do with CryptoJS, but is very simple.

Please check out your change node "Assign Variables".
In there you have set msg.salt = "payload.salt"
You set it to the string, not to the content of the variable.

Kind regards,

Urs.

Yes, the results are the same from the debug node but when I run it through the function node the results are still different. And I didn't realize that I set the change node to string, but it didn't fix anything.

When I run it with the correct inputs, the functon node kicks out

1/5/2021, 8:58:33 AM node: Auth Function
function : (error)

TypeError: Cannot read property 'SHA256' of undefined"

so how did you install it to use?

I installed it by adding some lines to my settings.js file.

functionGlobalContext: {
        // os:require('os'),
        // jfive:require("johnny-five"),
        // j5board:require("johnny-five").Board({repl:false})
		//gcm:require('node-gcm'),
		fs:require('fs'),
        cryptojs:require('crypto-js')
    },

I got something sort of working by assigning the variables in a function node, but now I'm running into the issue that the output changes when I assign a variable to the password in the function node vs when I just enter it as a string. The password is taken from a JSON config and put into the flow.password variable, and then I'm trying to load it into the function node.

msg.password = flow.password; (this is assigned to password in another part of the flow)
msg.password = "password";

I get two different results, even though the strings are the same.

Is there any reason you didnt just use one of the ready made cryptojs node-red nodes?

e.g. node-red-contrib-crypto-js-plus (node) - Node-RED

Even more: Library - Node-RED

It was just simpler to install it, and I could do everything in one function node. I tried using the ready-made nodes but I got a complete different result than what I'm expecting. And I think it's more efficient since everything is done at once in one function node.

How? to add a node module, you need to drop to command line, modify settings.js and you need to have good knowledge of JS.

The node-red node is simply installed by one click in the pallete.

The major selling point of node-red is a graphical wiring tool that helps you (and others) visually design a data flow. If you hide away functionality in a function node, you lose many of the benefits of node-red.

Anyway, that's not the point, for me it works just fine and it's better for me. I'm still having issues passing in the password as I mentioned earlier.

the bug is in your change node:

1 Like

Yep I realized that, and I fixed it. But the same thing still happens.

Worked for me, can you provide your current flow?

[{"id":"755f0b8.5893ff4","type":"inject","z":"4c0216e9.207cb8","name":"Manual Entry","props":[{"p":"password","v":"password","vt":"str"},{"p":"salt","v":"aszng9OoS6ybw9yTW2WR4GySMNdM3srSQ4KE70aungY=","vt":"str"},{"p":"challenge","v":"KSO+hOFs1q5SkEnx8bvp67Om2zyHDD6ZJF4NHAa3R94=","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":950,"y":3760,"wires":[["786daa7f.3fe284"]]},{"id":"36ed9ba2.56be04","type":"inject","z":"4c0216e9.207cb8","name":"Variable","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{     \"authRequired\": true,     \"challenge\": \"KSO+hOFs1q5SkEnx8bvp67Om2zyHDD6ZJF4NHAa3R94=\",     \"message-id\": \"f8100636.83edd8\",     \"salt\": \"aszng9OoS6ybw9yTW2WR4GySMNdM3srSQ4KE70aungY=\",     \"status\": \"ok\" }","payloadType":"json","x":920,"y":3800,"wires":[["b699085c.1bbdd8"]]},{"id":"786daa7f.3fe284","type":"function","z":"4c0216e9.207cb8","name":"Auth Function","func":"var CryptoJS = context.global.cryptojs;\n\nvar secret_hash = CryptoJS.SHA256(msg.password + msg.salt);\nvar secret = CryptoJS.enc.Base64.stringify(secret_hash);\n\nvar auth_response_hash = CryptoJS.SHA256(secret + msg.challenge);\nvar auth_response = CryptoJS.enc.Base64.stringify(auth_response_hash);\n\nmsg.payload = auth_response;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1330,"y":3780,"wires":[["b958d436.f24a48"]]},{"id":"b958d436.f24a48","type":"debug","z":"4c0216e9.207cb8","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1520,"y":3780,"wires":[]},{"id":"b699085c.1bbdd8","type":"change","z":"4c0216e9.207cb8","name":"Assign Variables","rules":[{"t":"set","p":"password","pt":"msg","to":"password","tot":"msg"},{"t":"set","p":"salt","pt":"msg","to":"payload.salt","tot":"msg"},{"t":"set","p":"challenge","pt":"msg","to":"payload.challenge","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1110,"y":3800,"wires":[["786daa7f.3fe284"]]}]

Both nodes have the same values, one is manually entered and one pulls the values from a message (which is what I want to do). But they each return a different string, even with the same values.

As I said a long time ago

(hint: the output is NOT the same)

Alright I managed to get a workaround working. Instead of using a change node to set the variables, it outputs the same result if I assign the variables with a function node instead. Don't know why it does this though, but it works and I can successfully authenticate with my program. Thanks all!

The problem in the change node iw you were setting msg.password to msg.password (which did not exist) when I beleive you meant to set msg.password to the string password.

The result was, via the change node, you did not pass in msg.password so the output from the crypto was different.

1 Like