2

Ok, so I am trying to generate a public and private key using crypto (https://nodejs.org/api/crypto.html#crypto_crypto_generatekeypair_type_options_callback)

The thing is, one of the parameters of the generateKeyPair is a callback function, and I can't get my code to wait for the callback to run. It runs eventually, but by then I already tried to use the data. The idea is to do something like this:

const _getKeyPair = (pwd: string): Object => {
    const { generateKeyPair }: any = require('crypto');

    const keyPair = { publicKey: '', privateKey: '' };
    generateKeyPair('rsa', {
        modulusLength: 4096,
        publicKeyEncoding: {
            type: 'spki',
            format: 'pem'
        },
        privateKeyEncoding: {
            type: 'pkcs8',
            format: 'pem',
            cipher: 'aes-256-cbc',
            passphrase: pwd
        }
    }, (err: Error, publicKey: string, privateKey: string) => {
        if (err) {
            throw err;
        }
        keyPair.publicKey = publicKey;
        keyPair.privateKey = privateKey;
    });

    return keyPair;
};

And call:

const keyPair = _getKeyPair('myPassword');
Icaro Mota
  • 912
  • 1
  • 12
  • 20
  • 1
    So, a Javascript function that retrieves a value asynchronously via a callback simply cannot return that value from the function. As you've already seen, the function returns BEFORE the callback is called and thus the value is not know when the function returns. Your options for communicating back the asynchronous value are a callback, a promise or an event. Details here [How do I return the response from an asynchronous call](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call/14220323#14220323). – jfriend00 Apr 28 '20 at 22:53
  • 1
    You don't "wait on a callback" in Javascript before returning. Even if you move to all promises and use `async/await`, the function is still returning a promise at the point of your first `await`, it's just the resolving of the promise that gets delayed and the caller has to use the promise with `await` or `.then()` to get the value. – jfriend00 Apr 28 '20 at 23:01

1 Answers1

5

crypto has two methods to generate key pair, an asynchronous one generateKeyPair and a synchronous one generateKeyPairSync which you can use without having to worry about callbacks if that's what you want. Another way is to wrap the method with a promise and use await. Something like:

const _getKeyPair = async (pwd) => {
  const { generateKeyPair } = require('crypto');

  return new Promise((resolve, reject) => {
    generateKeyPair('rsa', {
      modulusLength: 4096,
      publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
      },
      privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem',
        cipher: 'aes-256-cbc',
        passphrase: pwd
      }
    }, (err, publicKey, privateKey) => {
      if (err) return reject(err);
      resolve({publicKey, privateKey});
    });
  });
};

async function main() {
  const keyPair = await _getKeyPair('myPassword');
}

main();
  • 4
    It should be noted that the reason the `crypto` module offers asynchronous (callback-based) operations is because some crypto operations are CPU-intensive and can block the event loop for an undesired amount of time. When you use the asynchronous versions, it passes the crypto operations off to the thread pool and the CPU intensive work is performed without blocking the event loop. So, it's not always the best choice to just skip over to the synchronous methods. – jfriend00 Apr 29 '20 at 00:05