I have a peculiar problem by following one of the tutorials on encrypting JWT.
Given the following code:
const crypto = require('crypto');
const jwt = require('jsonwebtoken');
const passphrase = 'diogenes';
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
});
const sign = ({ messageId, tradeId, sessionToken }) => {
const token = jwt.sign(
{ messageId, tradeId, sessionToken },
passphrase,
{ expiresIn: '10h' }
);
return token;
};
const verify = (jwtToken) => {
const token = jwt.verify(jwtToken, passphrase);
return token;
};
const signedToken = sign({ messageId: '1', tradeId: '2', sessionToken: '3' });
const encryptedToken = crypto.publicEncrypt(publicKey, Buffer.from(signedToken, 'base64'));
const decryptedToken = crypto.privateDecrypt(privateKey, encryptedToken);
console.log(decryptedToken.toString('base64'));
console.log(signedToken);
The values I am getting from decrypting are slightly different, not much, but enough to make token inverifiable.
For example:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJtZXNzYWdlSWQiOiIxIiwidHJhZGVJZCI6IjIiLCJzZXNzaW9uVG9rZW4iOiIzIiwiaWF0IjoxNTczNTUxMDU4LCJleHAiOjE1NzM1ODcwNTh9zXIjsO8ExSOsmuGLzDh8JgclLjykiZjKBEiJ6mzLMAg=
versus the original:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXNzYWdlSWQiOiIxIiwidHJhZGVJZCI6IjIiLCJzZXNzaW9uVG9rZW4iOiIzIiwiaWF0IjoxNTczNTUxMDU4LCJleHAiOjE1NzM1ODcwNTh9.zXIjsO8ExSOsmuGLzDh8JgclLjykiZjKBEiJ6mzLMAg
What is going on here?
A JSON Web Token (JWT) consists of three parts separated by a dot (header, payload, signature), each of which is Base64Url-encoded, see What is the JSON Web Token structure?. Therefore, signedToken cannot be read into a buffer with the following statement:
Buffer.from(signedToken, 'base64')
which expects exactly one Base64 encoded string (here). The easiest way is to use the binary-encoding (which corresponds to the latin1- or ISO-8859-1-encoding) when reading into the buffer, since the individual parts are Base64-encoded and therefore compatible with this encoding:
const encryptedToken = crypto.publicEncrypt(publicKey, Buffer.from(signedToken, 'binary'));
and also for the output:
console.log(decryptedToken.toString('binary'));
Then both outputs are identical.
Related
I am trying to rewrite old NodeJs encryption algorithm from
crypto.createDecipheriv(algorithm, key, iv[, options])
into webcrypto
subtle.decrypt(algorithm, key, data)
This code work good enough with AES-128-CTR algorithm
const algorithm = 'aes-128-ctr';
const iv = '0123456789ABCDEF0123456789ABCDEF';
const privateKey = '16Random_Letters';
const hexBufferFromIv = Buffer.from(iv, 'hex');
const utfBufferFromPrivateKey = Buffer.from(privateKey, 'utf8');
function oldEncryptData(data: string): string {
const cipher = createCipheriv(
algorithm,
utfBufferFromPrivateKey,
hexBufferFromIv,
);
let crypted = cipher.update(data, 'utf8', 'base64');
crypted += cipher.final('base64');
return crypted;
}
function oldDecryptData(data: string): string {
const decipher = createDecipheriv(
algorithm,
utfBufferFromPrivateKey,
hexBufferFromIv,
);
let dec = decipher.update(data, 'base64', 'utf8');
dec += decipher.final('utf8');
return dec;
}
async function testDecrypt() {
const sourceText = `any text to encrypt!`;
const encryptedText = oldEncryptData(sourceText);
const decryptedText = oldDecryptData(encryptedText);
return sourceText === decryptedText;
}
testDecrypt().then(console.log);
Right now I test this code and WebCrypto examples in nodejs, but as a final result I wont to move webCrypto.subtle.decrypt functionality into NGINX njs and as I know, njs doesn't support other options for decryption except for WebCrypto.
Interface for WebCrypto decrypt for AES-CTR in general looks like
const data = await crypto.subtle.decrypt(
{
name: "AES-CTR",
counter, // BufferSource
length: 128, // 1-128
},
key, // AES key
encData, // BufferSource
);
And I don't undersatnd.
counter is the same thing as the Initialization vector in createDecipheriv method?
How I should generate key for subtle.decrypt method from the same passphrase?
Do I need to do any additional transformation from or to base64 or utf8 encoding to reproduce input and output encoding in cipher.update(data, 'utf8', 'base64'); and in decipher.update(data, 'base64', 'utf8'); methods?
Thanks Topaco for hints. I'll write a more complete answer. Maybe it will be useful for someone.
Yes, Initialization vector and counter can be treated as the same thing.
For generating a key from the same passphrase you should use importKey method. And you should sent the same ArrayBuffer from the passphrase as in createCipheriv method.
Yes, if your old method used some specific encoding and decoding, you should repeat the same encoding/decoding logic after Webcrypto.SubtleCrypto.encrypt() and decrypt() methods.
Full workable example may looks something like
import { webcrypto } from 'crypto';
const iv = '0123456789ABCDEF0123456789ABCDEF';
const privateKey = '16Random_Letters';
const hexBufferFromIv = Buffer.from(iv, 'hex');
const utfBufferFromPrivateKey = Buffer.from(privateKey, 'utf8');
async function generateKeyFromPassPhrase(): Promise<CryptoKey> {
return webcrypto.subtle.importKey(
'raw',
utfBufferFromPrivateKey,
{
name: 'AES-CTR',
},
true,
['decrypt', 'encrypt'],
);
}
async function newEncryptData(data: string): Promise<string> {
const key = await generateKeyFromPassPhrase();
const encryptResult = await webcrypto.subtle.encrypt(
{
name: 'AES-CTR',
length: 128,
counter: hexBufferFromIv,
},
key,
Buffer.from(data),
);
return Buffer.from(encryptResult).toString('base64');
}
async function newDecryptData(data: string): Promise<string> {
const key = await generateKeyFromPassPhrase();
const decryptResult = await webcrypto.subtle.decrypt(
{
name: 'AES-CTR',
length: 128,
counter: hexBufferFromIv,
},
key,
Buffer.from(data, 'base64'),
);
return Buffer.from(decryptResult).toString();
}
async function testDecrypt() {
const sourceText = `any text to encrypt!`;
const encrypted2 = await newEncryptData(sourceText);
const decrypted2 = await newDecryptData(encrypted2);
return sourceText === decrypted2;
}
testDecrypt().then(console.log);
I am trying to encrypt Credit Card data of customer to AES 256 CBC format but anytime I I call the API I get this error:
RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code: ERR_INVALID_ARG_TYPE
at ServerResponse.writeHead (_http_server.js:259:11)
at ServerResponse._implicitHeader (_http_server.js:250:8)
This is my code for the encryption:
const crypto = require('crypto');
const encryptionType = 'aes-256-cbc';
const encryptionEncoding = 'base64';
const bufferEncryption = 'utf8';
export class AesEncryption {
AesKey: string;
AesIV: string;
init() {
this.AesKey = process.env.SECRET as string;
this.AesIV = process.env.SECRET?.slice(0, 16) as string;
}
encrypt(jsonObject: Object): string {
const val = JSON.stringify(jsonObject);
const key = Buffer.from(this.AesKey, bufferEncryption);
const iv = Buffer.from(this.AesIV, bufferEncryption);
const cipher = crypto.createCipheriv(encryptionType, key, iv);
let encrypted = cipher.update(val, bufferEncryption, encryptionEncoding);
encrypted += cipher.final(encryptionEncoding);
return encrypted;
}
}
This is the code of where I am using it:
public async createPayment(data: IPaymentDetails): Promise<IPaymentDetails> {
try {
PaymentService.checkPaymentRequiredFields(data);
data.encryptedData = new AesEncryption().encrypt(data.card)
console.log(data.encryptedData)
...
headers: {
'Content-Type': 'application/json',
Cookie: 'PHPSESSID=7hnkto3se3mlsbnht755ok2ak6',
},
data: JSON.stringify({
merchantId: data.merchantId,
method: 'Card',
id: data.trans_id,
encryptedData: data.encryptedData,
}),
})
Anytime I call the API I get the above error.
The problem is because the key and iv from process.env is not updating correctly, so it was throwing undefined.
I have to pass the process.env.SECRET directly into the function instead of passing them inside a variable.
It worked.
I'm having troubles verifying signatures created by the Web Crypto API.
Here is the code I'm using to generate RSA keys in the browser:
let keys;
const generateKeys = async () => {
const options = {
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: { name: 'SHA-256' },
};
keys = await window.crypto.subtle.generateKey(
options,
false, // non-exportable (public key still exportable)
['sign', 'verify'],
);
};
And to export the public key:
const exportPublicKey = async () => {
const publicKey = await window.crypto.subtle.exportKey('spki', keys.publicKey);
let body = window.btoa(String.fromCharCode(...new Uint8Array(publicKey)));
body = body.match(/.{1,64}/g).join('\n');
return `-----BEGIN PUBLIC KEY-----\n${body}\n-----END PUBLIC KEY-----`;
// Output:
//
// -----BEGIN PUBLIC KEY-----
// MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAx7J3SUG4sq/HSGIaGZWY
// 8b26cfEpVFYHoDUDUORIJzA/fLE9aj+uOKpGUTSfW69rMm7DAOLDz05KaEJJSI5+
// YbDPr2S82A2ByHHQt+Vu168sGz4noXTTSX2HIdVutaR/IJ0a5pNOa1vRR4MUW/ZO
// YaRir3yC5YXgcFLwwQaifNZ3lZ7WndbYEjTGOcieQQ81IUP2221PZCJI52S95nYm
// VfslsLiPhOFH7XhGSqelGYDi0cKyl0p6dKvYxFswfKKLTuWnu2BEFLjVq4S5Y9Ob
// SGm0KL/8g7pAqjac2sMzzhHtxZ+7k8tynzAf4slJJhHMm5U4DcSelTe5zOkprCJg
// muyv0H1Acb3tfXsBwfURjiE0cvSMhfum5I5epF+f139tsr1zNF24F2WgvEZZbXcG
// g1LveGCJ/0BY0pzE71DU2SYiUhl+HGDv2u32vJO80jCDf2lu7izEt544a+XE+2X0
// zVpwjNQGa2Nd4ApGosa1fbcS5MsEdbyrjMf80SAmOeb9g3y5Zt2MY7M0Njxbvmmd
// mF20PkklpH0L01lhg2AGma4o4ojolYHzDoM5a531xTw1fZIdgbSTowz0SlAHAKD3
// c2KCCsKlBbFcqy4q7yNX63SqmI3sNA3kTH9CQJdBloRvV103Le9C0iY8CAWQmow5
// N/sDJUabgOMqe9yopSjb7LUCAwEAAQ==
// -----END PUBLIC KEY-----
};
To sign a message:
const generateHash = async (message) => {
const encoder = new TextEncoder();
const buffer = encoder.encode(message);
const digest = await window.crypto.subtle.digest('SHA-256', buffer);
return digest;
};
const signMessage = async (message) => {
const { privateKey } = keys;
const digest = await generateHash(message);
const signature = await window.crypto.subtle.sign('RSASSA-PKCS1-v1_5', privateKey, digest);
return signature;
};
To verify the message in browser:
const verifyMessage = async (signature, message) => {
const { publicKey } = keys;
const digest = await generateHash(message);
const result = await window.crypto.subtle.verify('RSASSA-PKCS1-v1_5', publicKey, signature, digest);
return result;
};
When the keys are created, the public key is exported and sent to the server. Later:
const message = 'test';
const signature = await signMessage(message);
await verifyMessage(signature, message); // true
sendToServer(message, bufferToHex(signature));
Since the signature is an ArrayBuffer, I convert it to hex with the following code:
const bufferToHex = input => [...new Uint8Array(input)]
.map(v => v.toString(16).padStart(2, '0')).join('');
On the server (NodeJS 8.11.0):
const publicKey = getPublicKey(userId);
const verifier = crypto.createVerify('RSA-SHA256');
verifier.update(message, 'utf-8');
const sigBuf = Buffer.from(signature, 'hex');
verifier.verify(publicKey, sigBuf); // false
I've been chasing down this issue for days and just cannot seem to figure it out. I've tried both RSA-SHA256 and sha256WithRSAEncryption for verification to no avail. Furthermore, no errors are being thrown. Any help would be enormously appreciated!
So I don't fully understand why this is the case, but to solve the issue I needed to convert the SHA hash from an ArrayBuffer into a hex string, then read back into an array buffer using TextEncoder.
const generateHash = async (message) => {
const encoder = new TextEncoder();
const buffer = encoder.encode(message);
const digest = await window.crypto.subtle.digest('SHA-256', buffer);
// Convert to hex string
return [...new Uint8Array(digest)]
.map(v => v.toString(16).padStart(2, '0')).join('');;
};
Then when signing:
const signMessage = async (message) => {
const encoder = new TextEncoder();
const { privateKey } = keys;
const digest = await generateHash(message);
const signature = await window.crypto.subtle.sign('RSASSA-PKCS1-v1_5', privateKey, encoder.encode(digest));
return signature;
};
The signature no longer verifies on the client but it verifies in node. 🤷♂️
The issue is that you are signing the hash of hash of your input when you should actually be signing hash of your input. SubtleCrypto internally hashes the input. There is no need for you to provide hashed input. Since you provided hashed input as an argument, SubtleCrypto hashed it again and then signed it which led to mismatch of signatures.
It may be useful to note that both crypto and crypto.subtle hash the message before signing, so hashing separately is not necessary.
Assuming you were able to create and load your keys properly, your code should look like this.
Browser
const message = 'hello'
const encoder = new TextEncoder()
const algorithmParameters = { name: 'RSASSA-PKCS1-v1_5' }
const signatureBytes = await window.crypto.subtle.sign(
algorithmParameters,
privateKey,
encoder.encode(message)
)
const base64Signature = window.btoa(
String.fromCharCode.apply(null, new Uint8Array(signatureBytes))
)
console.log(base64Signature)
// TiJZTTihhUYAIlOm2PpnvJa/+15WOX2U0iKJ2LXsLecvohhRIWnwFfdHy4ci10mcv/UQgf2+bFf9lfFZUlPPdzckBNfXIqAjafM8XquJiw/t1v+pEGtJpaGASlzuWuL37gp3k8ux3l6zBKKbBVPPASkHVhz37uY1AXeMblfRbFE=
Node
This implementation is using crypto, but you could use the crypto.subtle to be more similar to the browser javascript syntax
const crypto = require('crypto')
const message = 'hello'
const base64Signature = 'TiJZTTihhUYAIlOm2PpnvJa/+15WOX2U0iKJ2LXsLecvohhRIWnwFfdHy4ci10mcv/UQgf2+bFf9lfFZUlPPdzckBNfXIqAjafM8XquJiw/t1v+pEGtJpaGASlzuWuL37gp3k8ux3l6zBKKbBVPPASkHVhz37uY1AXeMblfRbFE='
const hashingAlgorithm = 'rsa-sha256'
const doesVerify = crypto.verify(
hashingAlgorithm,
Buffer.from(message),
{ key: publicKey },
Buffer.from(base64Signature, 'base64')
);
console.log(doesVerify)
// true
Not a direct answer but it might just be easier to use this: https://www.npmjs.com/package/#peculiar/webcrypto so your code on client and server is consistent while addressing this problem at the same time.
I see how to create HMAC 256 encrypted JWTs in NodeJS using Crypto, and the jsonwebtoken library. It's pretty easy
//encrypt & sign with HS256
const jwt = require('jsonwebtoken');
const pass = crypto.randomBytes(256).toString('hex');
const A = {algorithm:'HS256'};
const token = jwt.sign({ foo: 'bar' }, pass, A);
//decrypt & verify
jwt.verify(token, pass, A, function(err, decoded)
{
console.log('decode ',decoded);
console.log('err ',err);
res.send({error:err, text:decoded});
});
I would like to replace 'pass' with an 'RSA 256 SHA', and A with {algorithm:'RS256'}
In node crypto JS's documentation I see the command
const sign = crypto.createSign('RSA-SHA256');
to create the rsa-sha256
However then the documentation has the function
getPrivateKeySomehow()
Which is not defined or part of crypto.getPrivateKeySomehow()
So I guess I just need help getting the RSA-SHA-256 string returned from crypto, so that I can pass that into jsonwebtoken to sign my JWT.
Note: I do not want to read a private.key from a static file on my server because i see having a single private key for all my users as too big a security risk, hence why i am generating my own 256 bytes passwords and storing them off-site (not included in this post)
also, i'm not sure if i should do something like this (without using something like openssl from command line?)
const begin = '-----BEGIN RSA PRIVATE KEY-----\n';
const enc = crypto.randomBytes(256).toString('base64') + '\n';
const end = '-----END RSA PRIVATE KEY-----'
const pass = sign.sign(begin + enc + end);
const A = {algorithm:'RS256'};
const token = jwt.sign({ foo: 'bar' }, pass, A);
Take a look at this example bellow:
signExample = (str) => {
crypto.generateKeyPair('rsa', {
modulusLength: 1024,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
}, (err, publicKey, privateKey) => {
// sign String
var signerObject = crypto.createSign("RSA-SHA256");
signerObject.update(str);
var signature = signerObject.sign({key:privateKey,padding:crypto.constants.RSA_PKCS1_PSS_PADDING}, "base64");
console.info("signature: %s", signature);
//verify String
var verifierObject = crypto.createVerify("RSA-SHA256");
verifierObject.update(str);
var verified = verifierObject.verify({key:publicKey, padding:crypto.constants.RSA_PKCS1_PSS_PADDING}, signature, "base64");
console.info("is signature ok?: %s", verified);
});
}
Steps:
First you create an key pair with crypto.generateKeyPair('rsa', { ... desired key options
Create a Sign object - crypto.createSign("RSA-SHA256")
The string wanted to be signed - SignerObject.update(str)
Sign the string with your private key - signerObject.sign(
Option to salt - padding:crypto.constants.RSA_PKCS1_PSS_PADDING
I have to generate two keys (private and public) to encrypt a text with the public and let the user with the private key decrypt the text.
Is it possible with the module Crypto?
nodejs v10.12 now supports this natively with crypto.generateKeyPair
const { generateKeyPair } = require('crypto');
generateKeyPair('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: 'top secret'
}
}, (err, publicKey, privateKey) => {
// Handle errors and use the generated key pair.
});
Use the crypto module from npm to generate KeyPair.
var crypto = require('crypto');
var prime_length = 60;
var diffHell = crypto.createDiffieHellman(prime_length);
diffHell.generateKeys('base64');
console.log("Public Key : " ,diffHell.getPublicKey('base64'));
console.log("Private Key : " ,diffHell.getPrivateKey('base64'));
console.log("Public Key : " ,diffHell.getPublicKey('hex'));
console.log("Private Key : " ,diffHell.getPrivateKey('hex'));
Above is a example snippet. To know more checkout documentation http://nodejs.org/api/crypto.html
The following code works, but I'm not a professional cryptographer, so some comments here would be useful.
I've used the ursa RSA module, instead of crypto.
I am concerned that if similar data were encrypted directly, without a pass of AES or similar, then it might be trivial to break this. Comments please...
var ursa = require('ursa');
var fs = require('fs');
// create a pair of keys (a private key contains both keys...)
var keys = ursa.generatePrivateKey();
console.log('keys:', keys);
// reconstitute the private key from a base64 encoding
var privPem = keys.toPrivatePem('base64');
console.log('privPem:', privPem);
var priv = ursa.createPrivateKey(privPem, '', 'base64');
// make a public key, to be used for encryption
var pubPem = keys.toPublicPem('base64');
console.log('pubPem:', pubPem);
var pub = ursa.createPublicKey(pubPem, 'base64');
// encrypt, with the public key, then decrypt with the private
var data = new Buffer('hello world');
console.log('data:', data);
var enc = pub.encrypt(data);
console.log('enc:', enc);
var unenc = priv.decrypt(enc);
console.log('unenc:', unenc);
After some further investigation http://en.wikipedia.org/w/index.php?title=RSA_%28cryptosystem%29§ion=12#Attacks_against_plain_RSA it looks like ursa already does padding.
const crypto = require('crypto');
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem'
}
});
If you know how to get what you want from OpenSSL, I think it's perfectly reasonable to run OpenSSL using Node's child_process.
var cp = require('child_process')
, assert = require('assert')
;
var privateKey, publicKey;
publicKey = '';
cp.exec('openssl genrsa 2048', function(err, stdout, stderr) {
assert.ok(!err);
privateKey = stdout;
console.log(privateKey);
makepub = cp.spawn('openssl', ['rsa', '-pubout']);
makepub.on('exit', function(code) {
assert.equal(code, 0);
console.log(publicKey);
});
makepub.stdout.on('data', function(data) {
publicKey += data;
});
makepub.stdout.setEncoding('ascii');
makepub.stdin.write(privateKey);
makepub.stdin.end();
});
I dont know if this helps but I also was looking to do something along these lines.
Here is what I came up with :
As mentioned in the answer by Nelson Owalo you can use the crypto library, as follows :
//import the methods
const { generateKeyPair, createSign, createVerify } = require("crypto");
//generate the key pair
generateKeyPair(
"rsa",
{
modulusLength: 2048, // It holds a number. It is the key size in bits and is applicable for RSA, and DSA algorithm only.
publicKeyEncoding: {
type: "pkcs1", //Note the type is pkcs1 not spki
format: "pem",
},
privateKeyEncoding: {
type: "pkcs1", //Note again the type is set to pkcs1
format: "pem",
//cipher: "aes-256-cbc", //Optional
//passphrase: "", //Optional
},
},
(err, publicKey, privateKey) => {
// Handle errors and use the generated key pair.
if (err) console.log("Error!", err);
console.log({
publicKey,
privateKey,
});//Print the keys to the console or save them to a file.
/*
* At this point you will have to pem files,
* the public key which will start with
* '-----BEGIN RSA PUBLIC KEY-----\n' +
* and the private key which will start with
* '-----BEGIN RSA PRIVATE KEY-----\n' +
*/
//Verify it works by signing some data and verifying it.
//Create some sample data that we want to sign
const verifiableData = "this need to be verified";
// The signature method takes the data we want to sign, the
// hashing algorithm, and the padding scheme, and generates
// a signature in the form of bytes
const signature = require("crypto").sign("sha256", Buffer.from(verifiableData),
{
key: privateKey,
padding: require("crypto").constants.RSA_PKCS1_PSS_PADDING,
});
//Convert the signature to base64 for storage.
console.log(signature.toString("base64"));
// To verify the data, we provide the same hashing algorithm and
// padding scheme we provided to generate the signature, along
// with the signature itself, the data that we want to
// verify against the signature, and the public key
const isVerified = require("crypto").verify(
"sha256",
Buffer.from(verifiableData),
{
key: publicKey,
padding: require("crypto").constants.RSA_PKCS1_PSS_PADDING,
},
Buffer.from(signature.toString("base64"), "base64")
);
// isVerified should be `true` if the signature is valid
console.log("signature verified: ", isVerified);
}
);
I think the key points are which algorithm is used, as older versions of the pem use pkcs1 not pkcs8. The beginning of the key helps identify the version of the key and also includes information on wither it is encrypted or not. Hope this helps!
I have not used it, but this may be useful:
http://ox.no/posts/diffie-hellman-support-in-node-js
Documentation is severely lacking on this (no examples that I could find).
You can use this rsa-json module. It just spawns a openssl process, so it is pretty dependent on the OS (it does not work by default on windows).
child_process route is a terrible and non-scalable solution imo. Stay away.
I chose to go with keypair instead.