Different result in NodeJS calculating MD5 hash using crypo - node.js

I am trying to get the MD5 has from a number in NodeJS using crypto but I am getting a different hash returned then I get from site where I can calculate the has.
According to http://onlinemd5.com/ the MD5 has for 1092000 is AF118C8D2A0D27A1D49582FDF6339B7C.
When I try to calculate the hash for that number in NodeJS it gives me a different result (ac4d61a5b76c96b00235a124dfd1bfd1). My code:
const crypto = require('crypto');
const num = 1092000;
const hash = crypto.createHash('md5').update(toString(num)).digest('hex');
console.log(hash);

If you convert it to a string normally it works:
const hash = crypto.createHash('md5').update(String(num)).digest('hex'); // or num.toString()
See the difference:
toString(num) = [object Undefined]
(1092000).toString() = "1092000"
If you console.log(this) in a Node env by default you will see that it is:
this = {} typeof = 'object'
this in a Node env is pointing at module.exports so you're calling this toString on the Object.prototype which is not the right thing to do a string conversion on anything other than module.exports.

Related

Using randomUUID() in Zapier to generate UUID

I'm using Zapier's code module to write some Nodejs to generate a UUID.
I know that I can use node's crypto "library" because I've used it in the past to hash some text (MD5) to send to an API endpoint. I also know that I can use the crypto function randomInt.
For example, the following will correctly without errors return a number in the stated range:
const crypto = require('crypto');
let num = crypto.randomInt(1, 7);
output = [{id: num}];
When I try to use the randomUUID function (documentation), like the following, I get the error "TypeError: crypto.randomUUID is not a function" from Zapier:
const crypto = require('crypto');
let uuid = crypto.randomUUID();
output = [{id: uuid}];
I almost gave up there, but tried one last weird thing:
const crypto = require('crypto');
let uuid = crypto.randomUUID; //changed this
output = [{id: uuid}];
Note that I removed the () and this didn't throw an error and returned something like:
LT6TvivKgpFu5Yk3OvQmti1Hq1aNy5ZM
That looks a lot like a proper UUID since it has the right number of characters, but not the expected hyphens like (for example) 88368f2a-d5db-47d8-a05f-534fab0a0045
So, two questions:
Why is Zapier saying that randomUUID() is not a function? Does it not support this or am I coding something weirdly wrong or not requiring something needed? Is there a different way to do this?
When I use randomUUID (no ()) is this actually a reliable UUID?
EDIT: more info from Zapier, they are saying that their logs show that the code step cannot find module 'uuid'
When I use randomUUID (no ()) is this actually a reliable UUID?
The value you're getting there is not a reliable UUID. UUIDs will contain only 0-9a-f characters, the example you have there doesn't match.
Sorry I can't help you with what's going wrong with the other part! You could maybe try something like this
let crypto;
try {
crypto = require('crypto');
} catch (err) {
console.log('crypto support is disabled!');
}
to make sure the crypto package is actually available and there's not some error being silently suppressed? You may also want to check the version, as randomUUID() appears to have been added in v14.17.0
Also nit but should probably be const uuid = crypto.randomUUID(); instead of let ;)

Node js equivalent to Python utf8, Sha1, base64

I have this piece of code in python3
payload = 'my URI'
payload_utf8 = payload.encode("utf-8")
print(payload_utf8)
payload_sha1 = hashlib.sha1(payload_utf8).digest()
print(payload_sha1)
payload_base64 = base64.b64encode(payload_sha1)
print(payload_base64)
I want the same result but in node.js. I have tried this
const payload = "my URI";
console.log(payload);
const payload_UTF8 = utf8.encode(payload);
console.log(payload_UTF8);
const payload_Sha = crypto.createHash('sha1').update(payload_UTF8).digest()
console.log(payload_Sha);
const payload_Base64 = Buffer.from(payload_Sha).toString('base64');
But the results isn't the same.
The results are the same, the only difference is that in the python example you're returning a byte array and in the Js example, you're returning a string. If you want to get the exact same result in string format you can use print(payload_base64.decode("utf-8")).

Argument of type '{}' is not assignable to parameter of type 'Uint8Array'

I'm trying to clone and run an opensource project repo and having hard time fixing this issue, npm start fails with "compile failed error' and its states the following reason.
Argument of type '{}' is not assignable to parameter of type 'Uint8Array'
const [encChallenge] = await waitEvent(socket, 'data')
const challenge = decrypt(encChallenge) //This line causes the error
Following in the decrypt function
/** Decrypt data used shared key */
function decrypt(data: Uint8Array) {
if (!sharedKey) return null
const nonce = data.slice(0, sodium.crypto_box_NONCEBYTES)
const box = data.slice(sodium.crypto_box_NONCEBYTES, data.length)
const msg = crypto.decrypt(box, nonce, sharedKey)
return msg
}
Changing the parameter to any solves it but I can't do that,
How can I convert my parameter to Unit8Array?
As long as encChallenge is a typed array represents an array of 8-bit unsigned integers then you should just be able to do:
const [encChallenge] = await waitEvent(socket, 'data')
const challenge = decrypt(new Uint8Array(encChallenge);)
really i would make waitEvent encChallenge be of strongly type Uint8Array in waitEvent method, then it's abstracted away and always that type if you reuse it again.

Generating ECDSA signature with Node.js/crypto

I have code that generates a concatenated (r-s) signature for the ECDSA signature using jsrsasign and a key in JWK format:
const sig = new Signature({ alg: 'SHA256withECDSA' });
sig.init(KEYUTIL.getKey(key));
sig.updateHex(dataBuffer.toString('hex'));
const asn1hexSig = sig.sign();
const concatSig = ECDSA.asn1SigToConcatSig(asn1hexSig);
return new Buffer(concatSig, 'hex');
Seems to work. I also have code that uses SubtleCrypto to achieve the same thing:
importEcdsaKey(key, 'sign') // importKey JWK -> raw
.then((privateKey) => subtle.sign(
{ name: 'ECDSA', hash: {name: 'SHA-256'} },
privateKey,
dataBuffer
))
These both return 128-byte buffers; and they cross-verify (i.e. I can verify jsrsasign signatures with SubtleCrypto and vice versa). However, when I use the Sign class in the Node.js crypto module, I seem to get something quite different.
key = require('jwk-to-pem')(key, {'private': true});
const sign = require('crypto').createSign('sha256');
sign.update(dataBuffer);
return sign.sign(key);
Here I get a buffer of variable length, roughly 70 bytes; it does not cross-verify with jsrsa (which bails complaining about an invalid length for an r-s signature).
How can I get an r-s signature, as generated by jsrsasign and SubtleCrypto, using Node crypto?
The answer turns out to be that the Node crypto module generates ASN.1/DER signatures, while other APIs like jsrsasign and SubtleCrypto produce a “concatenated” signature. In both cases, the signature is a concatenation of (r, s). The difference is that ASN.1 does so with the minimum number of bytes, plus some payload length data; while the P1363 format uses two 32-bit hex encoded integers, zero-padding them if necessary.
The below solution assumes that the “canonical” format is the concatenated style used by SubtleCrypto.
const asn1 = require('asn1.js');
const BN = require('bn.js');
const crypto = require('crypto');
const EcdsaDerSig = asn1.define('ECPrivateKey', function() {
return this.seq().obj(
this.key('r').int(),
this.key('s').int()
);
});
function asn1SigSigToConcatSig(asn1SigBuffer) {
const rsSig = EcdsaDerSig.decode(asn1SigBuffer, 'der');
return Buffer.concat([
rsSig.r.toArrayLike(Buffer, 'be', 32),
rsSig.s.toArrayLike(Buffer, 'be', 32)
]);
}
function concatSigToAsn1SigSig(concatSigBuffer) {
const r = new BN(concatSigBuffer.slice(0, 32).toString('hex'), 16, 'be');
const s = new BN(concatSigBuffer.slice(32).toString('hex'), 16, 'be');
return EcdsaDerSig.encode({r, s}, 'der');
}
function ecdsaSign(hashBuffer, key) {
const sign = crypto.createSign('sha256');
sign.update(asBuffer(hashBuffer));
const asn1SigBuffer = sign.sign(key, 'buffer');
return asn1SigSigToConcatSig(asn1SigBuffer);
}
function ecdsaVerify(data, signature, key) {
const verify = crypto.createVerify('SHA256');
verify.update(data);
const asn1sig = concatSigToAsn1Sig(signature);
return verify.verify(key, new Buffer(asn1sig, 'hex'));
}
Figured it out thanks to
https://crypto.stackexchange.com/questions/1795/how-can-i-convert-a-der-ecdsa-signature-to-asn-1
ECDSA signatures between Node.js and WebCrypto appear to be incompatible?

Using SHA-256 with NodeJS Crypto

I'm trying to hash a variable in NodeJS like so:
var crypto = require('crypto');
var hash = crypto.createHash('sha256');
var code = 'bacon';
code = hash.update(code);
code = hash.digest(code);
console.log(code);
But looks like I have misunderstood the docs as the console.log doesn't log a hashed version of bacon but just some information about SlowBuffer.
What's the correct way to do this?
base64:
var crypto = require('crypto');
const hash = crypto.createHash('sha256').update(input).digest('base64');
hex:
var crypto = require('crypto')
const hash = crypto.createHash('sha256').update(input).digest('hex');
nodejs (8) ref
const crypto = require('crypto');
const hash = crypto.createHash('sha256');
hash.on('readable', () => {
const data = hash.read();
if (data) {
console.log(data.toString('hex'));
// Prints:
// 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
}
});
hash.write('some data to hash');
hash.end();
you can use, like this, in here create a reset token (resetToken), this token is used to create a hex version.in database, you can store hex version.
// Generate token
const resetToken = crypto.randomBytes(20).toString('hex');
// Hash token and set to resetPasswordToken field
this.resetPasswordToken = crypto
.createHash('sha256')
.update(resetToken)
.digest('hex');
console.log(resetToken )
Similar to the answers above, but this shows how to do multiple writes; for example if you read line-by-line from a file and then add each line to the hash computation as a separate operation.
In my example, I also trim newlines / skip empty lines (optional):
const {createHash} = require('crypto');
// lines: array of strings
function computeSHA256(lines) {
const hash = createHash('sha256');
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim(); // remove leading/trailing whitespace
if (line === '') continue; // skip empty lines
hash.write(line); // write a single line to the buffer
}
return hash.digest('base64'); // returns hash as string
}
I use this code ensure generated lines of a file aren't edited by someone manually. To do this, I write the lines out, append a line like sha256:<hash> with the sha265-sum, and then, upon next run, verify the hash of those lines matches said sha265-sum.

Resources