Node.js cypher and OpenSSL differ - node.js

Nodejs Code
var crypto = require("crypto");
var cypher = crypto.createCipher("aes192", "pass");
var out = cypher.update("TEST1","utf8", "binary");
out += cypher.final("binary");
console.log(out);
NODE OUTPUT:
´_ËT~R dE{
Command Line:
echo -n "TEST1" | openssl enc -aes192
CLI OUTPUT:
Salted__?
????X-N??R?*a8 P9?t%
What am I doing wrong?
PD: Yeah, I know those are binary outputs but still they clearly don't match.

You're missing the -nosalt flag to openssl.

Related

NodeJS SHA1 get raw output (PHP SHA1 raw output equivalent)

In PHP, the code below returns the raw output of the SHA1 of the "string"
sha1("string", true);
What is the nodeJS equivalent of getting the SHA1 raw output?
Edit: I made some test and this line:
crypto.createHash('sha1').update('string').digest('base64');
generates same output as php's
base64_encode(sha1('string', true));
My issue occurs when I try to concatenate a string and the result of sha1, the get the sha1 again:
base64_encode(sha1(sha1("string", true) . "another string", true))
Different with nodejs:
var stringhash = crypto.createHash('sha1').update('string').digest();
crypto.createHash('sha1').update("another string" + stringhash).digest('base64')
Something like this:
const crypto = require('crypto');
let digest = crypto.createHash('sha1').update('string').digest();
process.stdout.write( digest );
EDIT: the equivalent of your second example:
let hash1 = crypto.createHash('sha1').update('string').digest();
let hash2 = crypto.createHash('sha1').update(hash1).update('another string');
let digest = hash2.digest('base64');

crypto, node 6 return different hash than node4

A upgrade nodeJS from 4.2.6 to 6.9.1 and crypto HMAC produce different output.
For example:
node 4.2.6:
crypto.createHmac('sha512', crypto_key_bytes).update(crypto_text).digest('hex')
.toUpperCase()
=>20404FCB6D86CDF0E38002DD8BC36596C2882EB48433C074F9DDC2F1F6D47748E1F26E062E2D17671C18B87FFEE1C72576B48CFA9A61AF447A2F4C1B06316616 is OK.
node 6.9.1:
crypto.createHmac('sha512',crypto_key_bytes).update(crypto_text)
.digest('hex').toUpperCase();
or
crypto.createHmac('sha512',crypto_key_bytes2).update(crypto_text,'binary')
.digest('hex').toUpperCase();
or
crypto.createHmac('sha512',crypto_key_bytes2)
.update(crypto_text,'utf-8').digest('hex').toUpperCase();<code
=>1D974668D0CB06B87C9645CF92161358951B224798015BAEE5A4BEDC54E88159E5082C6E3BB1D8612C904C33F9A80A88642ECB99B69B7BBDC5EC633119169DBE is NOT OK
Do you have an idea ?
Thank you !
I believe the problem you have is in the data, not the Node.js HMAC implementation.
I did a quick test with 4.2.6 and 6.9.1 and they do produce identical 'sha512' HMACs indeed.
Code
var crypto = require('crypto');
console.log(
crypto.createHmac('sha512',"key").update("text").digest('hex').toUpperCase()
);
Output
./node --version
4.2.6
./nodejs hmac
B585312ACDD38EC13F13BB4CBA35A75473F32B6AE4A0303926815BD43D7A2631516B2B031F34D89EDA853E948D5057DE54A880C16697242DBE6A1AD994BC4E5D
./node --version
v6.9.1
./nodejs hmac
B585312ACDD38EC13F13BB4CBA35A75473F32B6AE4A0303926815BD43D7A2631516B2B031F34D89EDA853E948D5057DE54A880C16697242DBE6A1AD994BC4E5D
The problem result from the function :
for(var k=0 ; k < crypto_key.length-1 ; k+=2){
tmp = parseInt(crypto_key.substr(k, 2), 16);
crypto_key_bytes.push(tmp);
}
correct by :
for(var k=0 ; k < crypto_key.length-1 ; k+=2){
tmp = parseInt(crypto_key.substr(k, 2), 16);
if (tmp>128) {
tmp = tmp-256;
}
crypto_key_bytes.push(tmp);
}`
The fonction parseInt() change from NodeJS 4.2.6 to 6.9.1..

Create a base64 md5 hash in nodejs equivalent to this openssl command

I have a linux command to create argument value, but I dont know how to convert it in nodejs. This is linux command line:
echo -n '2147483647/s/link127.0.0.1 secret' | \
openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =
and result when execute it in terminal
_e4Nc3iduzkWRm01TBBNYw
Please tell me how to make it in nodejs without child process.
Any terminal command can be executed in Node.js by using the exec or spawn. In this case, exec will probably be your best bet. Follow the pattern below just replace my command to list the directories in /home/username with whatever command you want:
var exec = require('child_process').exec;
exec("ls /home/username", function (error, stdout, stderr) {
console.log("error: ", error);
console.log("stdout: ", stdout);
console.log("stderr: ", stderr);
});
Done
var mysecretkey = "secret";
var path = "/s/link";
var ip = '127.0.0.1';
var time = '2147483647';
var path = time + path + ip + ' ' + mysecretkey;
var crypto = require('crypto');
var md5sum = crypto.createHash('md5');
var d = md5sum.update(path).digest('base64');
//#echo -n '2147483647/s/link127.0.0.1 secret' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =
var test = d.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
console.log(test);

Verify signature on a file nodejs

I don't understand why verify always returns false for me... running openssl will return that everything is just dandy
$ openssl dgst -md5 -verify mykey.pub -signature signature message.txt
Verified OK
However, running my code in the node results in the verification to be false
var fs = require('fs');
var path = require('path');
var crypto = require('crypto');
//pass in arguments
var args = process.argv.slice(2);
fs.readFile(args[0], 'ascii', function(err,signature){
if(err){console.log(err);}
fs.readFile(args[1], 'ascii', function(err,message){
if(err){console.log(err);}
fs.readFile(args[2], 'ascii', function(err,publickey){
if(err){console.log(err);}
verify(signature, message, publickey);
});
});
});
//verify function
var verify = function(signature, message, publickey){
//everything prints out right
console.log(signature.toString() + '\n');
console.log(message.toString() + '\n');
console.log(publickey.toString() + '\n');
//using md5
var verifier = crypto.createVerify('md5');
verifier.update(message.toString());
var WHAT = verifier.verify(publickey.toString(), signature.toString(), 'binary');
console.log(WHAT);
};
Looking at the output results in this
$ node verifyHash signature message.txt mykey.pub
B`⌂ pgfs☼st;3_V1I☻l♂[V5 =C♠~o▲§►rH`KZ7#♦♠LiQ⌂xFw
▼♣"↓d;.H4+↕$WZF▲◄Ow▲r⌂,
j]U↕6►vQm$7v&^^uF↨/ma2F→*n
►¶o'$jN!☼↑☺aV+↔e^qH▲A►rmx.
HEllo
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDgn0PrHxivu0zgG8pp66yMwxJ
MyYsdocVNpZ+673WlRlN0NKQRkI7+F7rYMG4KWL0pDBeOahOggxNVTNV9cxkCKce
Gp37+ZED5HiHKDll4tVoGVSDLaW0BBVe1TzfJSS64fvN/OssyjKffD5ExpLE4O5o
Vv7robQ0JxzYfbz2FQIDAQAB
-----END PUBLIC KEY-----
false
What am I doing wrong?
You cannot read the signature as ASCII, as it contains binary data (byte values > 128). These will get stripped then [1].
As the verifier is a stream.Writable the easiest solution is to use fs.createReadStream and then pipe to pipe it into the verifier.
See this REPL transcript:
> crypto = require('crypto'); undefined
undefined
> fs = require('fs'); undefined
undefined
> verifier = crypto.createVerify('md5'); undefined
undefined
> fs.createReadStream('file').pipe(verifier); undefined
undefined
> verifier.verify(fs.readFileSync('publickey.pem'), fs.readFileSync('signature.sign'), 'binary');
true
[1]
> new Buffer(fs.readFileSync('signature.sign', 'binary')).toString('hex');
'3632c3a6c28dc2806fc2bb563dc3bb51c38b537dc2871ac394c288405dc2b87634c2b5c3be53157273c2bfc3acc2b9c398c2a05e506ec3a6c3b2c2a9c3bf4bc280c28133c298c281c39a07c3acc2a612c2b0c2bec38fc28ac2bbc2b941504fc3bc22c2a0c3910325c38c5f581d4c7f4fc3a3c389c2b4c3b72e36c29b3d29c295c2b4c28755c38158c3af0f0e08c3bbc29f3bc3bc5e57c288c29d287ec3bf1bc39864c2867cc3867bc3a03ec3bd5a2806c3bd55c2a0c29a12c3aac2b675c284500504c38832c291c383c3b933222961c2b3c3bac2a3583737c3861cc392c39373c2bac298c2b96b6c1dc29f3fc2b1c387c397c39719c29fc39ec28c02c29d3cc396c2abc3923bc28e621032c3bec298c2a877c3bbc2ae6fc38cc3b4c2b1c387c390c39d03753bc28ac2b0c2b64f3fc3a7c3a254c398c3b91ec2935922c3aac2bdc2aa41c295c39519c2b8c3bdc2a02d74c2bfc38ec3aa60c2b87c433e1dc28b2351c3b8c2b54a237cc29703521dc3a3c2b34958c2a4c3a9c2a410c2b8c39e5dc3af2c6a27c2987e'
> new Buffer(fs.readFileSync('signature.sign', 'ascii')).toString('hex');
'3632660d006f3b563d7b514b537d071a5408405d387634357e531572733f6c3958205e506e6672297f4b00013318015a076c2612303e4f0a3b3941504f7c22205103254c5f581d4c7f4f634934772e361b3d291534075541586f0f0e087b1f3b7c5e57081d287e7f1b5864067c467b603e7d5a28067d55201a126a367504500504483211437933222961337a23583737461c5253733a18396b6c1d1f3f31475757191f5e0c021d3c562b523b0e6210327e1828777b2e6f4c743147505d03753b0a30364f3f67625458791e1359226a3d2a41155519387d202d743f4e6a60387c433e1d0b235178354a237c1703521d6333495824692410385e5d6f2c6a27187e'
You can also try to use Windows/macOS npm package util sign-check for executables/files signature verification.
It uses built-in OS mechanisms to verify is code signed (codesign --verify command for macOS and WinVerifyTrust API implementation for Windows).
For sign verification you can just use:
const SignCheck = require('sign-check');
const somePath = 'some/path/for/test';
SignCheck.checkMac(somePath).then(
(isSigned) => {
console.log('File sign status ' + isSigned);
},
(error) => {
console.log(error);
}
);
Or checkWin function for Windows platform.

Node.js and crypto library

I'm having weird issues with Node's crypto library. I wrote this simple AES testing script:
var cipher = crypto.createCipher('aes-256-cbc','InmbuvP6Z8')
var text = "123|123123123123123";
cipher.update(text,'utf8','hex')
var crypted = cipher.final('hex')
var decipher = crypto.createDecipher('aes-256-cbc','InmbuvP6Z8')
decipher.update(crypted,'hex','utf8')
var dec = decipher.final('utf8')
When I do console.log(dec), it's null. For some reason if I set test to "123|123123", it works. So why does "123|123123" work but "123|123123123123123" doesn't?
You need to store the return from cipher.update as well as cipher.final to be sure you have everything.
cipher.update "returns the enciphered contents, and can be called many times with new data as it is streamed":
http://nodejs.org/docs/v0.2.5/api.html#cipher-update-247
cipher.final "returns any remaining enciphered contents".
I think you just append the results with each call like this:
var crypto = require('crypto');
var cipher = crypto.createCipher('aes-256-cbc','InmbuvP6Z8');
var text = "123|123123123123123";
var crypted = cipher.update(text,'utf8','hex');
crypted += cipher.final('hex');
var decipher = crypto.createDecipher('aes-256-cbc','InmbuvP6Z8');
var dec = decipher.update(crypted,'hex','utf8');
dec += decipher.final('utf8');
I get '12443a347e8e5b46caba9f7afc93d71287fbf11169e8556c6bb9c51760d5c585' for crypted and '123|123123123123123' for dec in the above with node v0.2.5
RandomEtc is correct, but just in case anyone stumbling on this question is using 'base64' as their encoding: Don't. Stick to 'hex'. At least as of 0.4.2, there's a bug that can result in corrupted data when 'base64' is used. See: https://github.com/joyent/node/issues/738/
Please note that the += operator will not work in later versions of node.js. Please follow the advice given in Node.js Crypto class returning different results with updated version and use Buffer.concat()

Resources