How to create a pair private/public keys using Node.js crypto?

node.jsNode Crypto

node.js Problem Overview


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?

node.js Solutions


Solution 1 - node.js

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.
});

Solution 2 - node.js

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

Solution 3 - node.js

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&section=12#Attacks_against_plain_RSA it looks like ursa already does padding.

Solution 4 - node.js

const crypto = require('crypto');

  const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
    modulusLength: 2048,
    publicKeyEncoding: {
      type: 'spki',
      format: 'pem'
    },
    privateKeyEncoding: {
      type: 'pkcs8',
      format: 'pem'
    }
  }); 

Solution 5 - node.js

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();  
});

Solution 6 - node.js

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!

Solution 7 - node.js

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).

Solution 8 - node.js

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).

Solution 9 - node.js

child_process route is a terrible and non-scalable solution imo. Stay away.

I chose to go with keypair instead.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDailView Question on Stackoverflow
Solution 1 - node.jsNelson OwaloView Answer on Stackoverflow
Solution 2 - node.jsAksView Answer on Stackoverflow
Solution 3 - node.jsfadedbeeView Answer on Stackoverflow
Solution 4 - node.jsNats_AyalaView Answer on Stackoverflow
Solution 5 - node.jskgilpinView Answer on Stackoverflow
Solution 6 - node.jsdreamingrainbowView Answer on Stackoverflow
Solution 7 - node.jsSteve CampbellView Answer on Stackoverflow
Solution 8 - node.jsGuidoView Answer on Stackoverflow
Solution 9 - node.jsredditmercView Answer on Stackoverflow