Get available hash algorithms in nodejs crypto module - node.js

I'd like to know if there is a way (API method for example) to know all available hash algorithms (and the exact input name) in NodeJs crypto module.
According to official docs, in createHash function it is said:
https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options
The algorithm is dependent on the available algorithms supported by
the version of OpenSSL on the platform. Examples are 'sha256',
'sha512', etc. On recent releases of OpenSSL, openssl list
-digest-algorithms (openssl list-message-digest-algorithms for older versions of OpenSSL) will display the available digest algorithms.
So depending the OpenSSL version in the node version I am running, I will have different hash algorithm options? Any way(like API method) to know available hash algorithms in the installed crypto module directly?
Thanks

Node's crypto has an api for getHashes() according to their documentation.
Sample list
let crypto = require('crypto');
let listOfSupportedHashes = crypto.getHashes();
console.log('Total supported hashes : ', listOfSupportedHashes.length);

Related

How does OpenSSL choose which ENGINE to use?

I have an application that dynamically links with OpenSSL 1.0.2 and TPM hardware with OpenSSL ENGINE implementation for RSA.
I use OpenSSL's dynamic ENGINE to register the TPM ENGINE. This is how the (simplified) code looks:
ENGINE_load_dynamic();
ENGINE *e = ENGINE_by_id("dynamic");
ENGINE_ctrl_cmd_string(e, "SO_PATH", path_to_libtpm, 0);
ENGINE_ctrl_cmd_string(e, "ID", "tpm2tss", 0);
ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0);
ENGINE_init(e);
ENGINE_ctrl_cmd(e, ...);
ENGINE_ctrl_cmd(e, ...);
ENGINE_register_all_complete();
ENGINE_finish(e);
ENGINE_free(e);
According to the man page, since I'm calling ENGINE_register_all_complete() instead of ENGINE_set_default_RSA, I am letting OpenSSL decide which implementation of RSA to use.
the next time OpenSSL tries to set up an RSA key, any bundled ENGINEs that implement RSA_METHOD will be passed to ENGINE_init() and if any of those succeed, that ENGINE will be set as the default for RSA use from then on
Will OpenSSL prioritize RSA implementation in a registered ENGINE over its own implementation?
What happens when there are several ENGINEs registered that provide implementations for the same algorithm? Will OpenSSL use the first ENGINE it is able to initialize?
Is there any guarantee that a registered ENGINE will be used if ENGINE_set_default_XXX is not called?
You can specify which engine to use via the openssl.cnf configfile
Or you can use the -engine parameter to specify an engine on the commandline.
From your C Code you can use ENGINE_by_id(engine_id);

Nodejs crypto.publicEncrypt yields different results on different machines

We are trying to encrypt and decrypt using an asymmetric key in AWS KMS. The configuration for the key is as follows:
In NodeJS, we use the public key to encrypt via the crypto.publicEncrypt:
const encryptRSAPayload = (buffer, publicKey) => {
const encryptedBuffer = crypto.publicEncrypt(
{
key: publicKey,
oaepHash: 'sha256',
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
},
buffer
);
return encryptedBuffer;
};
And we use the function like this (the public key is read from a local file during the minimal repro):
const plainText = '12345678910';
const encrypted = await encryptRSAPayload(Buffer.from(plainText), publicKey);
Now, four developers have ran the exact same code (zipped, with public key etc), this is happening:
NOTE: All of the developers are on the latest OSX system.
Two of us can use AWS to decrypt whatever we produce from the encrypt function, and the other two can not (failing with IvalidCiphertext: null) from AWS.
The encrypted, base64 string from one of the machines that can not encrypt -> decrypt, can not be decrypted on any other machine.
The encrypted base64 string from one of the machines that can encrypt -> decrypt, can be decrypted in aws from any machine.
By now, ive spent two days on this and am a bit lost on what to do. Any ideas?
Problem solved after a few more days of debugging. The problem stemmed from the shipped version of OpenSSL that comes with OSX. For me, that was LibreSSL 2.8, which does not include some of the padding flags used in OAEP nor changing the hash to sha256 (instead of sha1).
The solution was:
Install OpenSSL via Homebrew and set the PATH env to use that version instead of the shipped version.
Reinstall any installed node version to re-link to the correct OpenSSL version.

NodeJS - Get certificate Chain from P7B file

I'm trying to take a CMS base64 encoded string, convert it into a pkcs7 file and extract the leaf and intermediate certificates using javascript/nodejs, similar to the following openssl command:
openssl pkcs7 -print_certs -in certificate.p7b -out certificate.cer
I've read almost every article and see solutions in other languages, but not for node. I understand you can achieve what I need using node-forge, but node-forge does not support ECC algorithms. Anyone know of any other solutions/npm packages that can help me accomplish this? Please help me. I'm very new to this.
Did you see PKI.js for Node.js? It is a pure JavaScript library implementing the formats that are used in PKI applications. It is based on the W3C Web Cryptography API with full support for all "Suite B" algorithms in CMS messages. Code snippet submitted by OP:
const cmsSignedBuffer = stringToArrayBuffer(fromBase64(token.signature));
const asn1 = asn1js.fromBER(cmsSignedBuffer);
const cmsContentSimpl = new pkijs.ContentInfo({ schema: asn1.result });
const cmsSignedSimpl = new pkijs.SignedData({ schema: cmsContentSimpl.content })
Another approach is to use a wrapper for openssl like openssl-nodejs, for example. The wrapper simply spawns a child process to invoke openssl. Thus, openssl must be installed on system where the Node.js application is deployed.

Public encryption in crypto on node 0.12

I need to encrypt (and decrypt) a string with a public key previously generated in nodejs (i'm using version 0.12) with crypto module, but i'm unable to do it.
For first i generated the keys in this way:
var diffHell = crypto.createDiffieHellman(60);
diffHell.generateKeys('base64');
var publicKey = diffHell.getPublicKey('base64'); //or whatever 'hex','binary'
var privateKey = diffHell.getPrivateKey('base64'); //or whatever 'hex','binary'
Then i tried to encrypt a string using the generated public key:
crypto.publicEncrypt({key: publicKey}, new Buffer(textToEncrypt));
Running this snippet, node throw this error:
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
at Error (native)
at Object.exports.publicEncrypt (crypto.js:362:18)
[...]
Reading it, I understand that the key must be in PEM format, but i can't find in the documentation how to tranform a public key in PEM.
So, How i can do that? Someone has done this yet?
Diffie-Hellman (Key Exchange) is an algorithm and protocol to derive a shared secret based on modular arithmetic. It is not a public-key cipher in the same way as RSA is. You cannot use Diffie-Hellman for crypto.publicEncrypt().
Node.js' Crypto module doesn't provide a way to generate a public-private RSA key pair, so you either need to use OpenSSL through child_process or use one of the many modules which provide this sort of thing (e.g. ursa).
You do not need to uses ursa for key generation. Instead you can generate keys with openssl then store the generated PEM keys on your server and try to load them in your script

Hex encode ECDSA keys in node.js

I'm building a nodejs app that talks to an API server. The API server requires that each request I make to it includes a X-Signature header using the prime256v1 ECDSA curve and sha256 hash on a particular set of data.
I looked through the crypto and tls documentation but didn't find anything suitable. I have successfully generated a private key with openssl ecparam -name prime256v1 -genkey but it is in PEM format. I have also generated a DER format key. Both of these include some extra metadata like the curve used and in the case of PEM, comments.
I can use these keys for signing operations on my side, but the server requires that I upload a public key using hex encoding (so the server can verify the signatures I make on my requests.)
Specifically the server wants something like the output of the following Python code:
from ecdsa import SigningKey
from binascii import hexlify
hexlify(SigningKey.from_pem(content).to_string())
Sample output for a pubkey (no newlines): c5bd76cd0cd948de17a31261567d219576e992d9066fe1a6bca97496dec634e2c8e06f8949773b300b9f73fabbbc7710d5d6691e96bcf3c9145e15daf6fe07b9
I would prefer not adding python as a dependency to my node app... anyone know of a way I can extract the binary data representing my private key from the PEM or DER files, so I can put it in a buffer and call buffer.toString('hex')? Or a way I can use the native crypto library to generate the ECDSA keypair? Or a library that would do the same?
openssl itself can print out the guts of things, in hex.
Doe the key change? sounds like you can just decode into hex one time, and use that? No need for dependencies - just paste the hex into your node source?

Resources