src/crypto/public_key/rsa.js
async function(B, E) {
    let key;
    E = new BN(E, 16);
    const webCrypto = util.getWebCryptoAll();

    // Native RSA keygen using Web Crypto
    if (webCrypto) {
      let keyPair;
      let keyGenOpt;
      if ((window.crypto && window.crypto.subtle) || window.msCrypto) {
        // current standard spec
        keyGenOpt = {
          name: 'RSASSA-PKCS1-v1_5',
          modulusLength: B, // the specified keysize in bits
          publicExponent: E.toArrayLike(Uint8Array), // take three bytes (max 65537) for exponent
          hash: {
            name: 'SHA-1' // not required for actual RSA keys, but for crypto api 'sign' and 'verify'
          }
        };
        keyPair = webCrypto.generateKey(keyGenOpt, true, ['sign', 'verify']);
        keyPair = await promisifyIE11Op(keyPair, 'Error generating RSA key pair.');
      } else if (window.crypto && window.crypto.webkitSubtle) {
        // outdated spec implemented by old Webkit
        keyGenOpt = {
          name: 'RSA-OAEP',
          modulusLength: B, // the specified keysize in bits
          publicExponent: E.toArrayLike(Uint8Array), // take three bytes (max 65537) for exponent
          hash: {
            name: 'SHA-1' // not required for actual RSA keys, but for crypto api 'sign' and 'verify'
          }
        };
        keyPair = await webCrypto.generateKey(keyGenOpt, true, ['encrypt', 'decrypt']);
      } else {
        throw new Error('Unknown WebCrypto implementation');
      }

      // export the generated keys as JsonWebKey (JWK)
      // https://tools.ietf.org/html/draft-ietf-jose-json-web-key-33
      let jwk = webCrypto.exportKey('jwk', keyPair.privateKey);
      jwk = await promisifyIE11Op(jwk, 'Error exporting RSA key pair.');

      // parse raw ArrayBuffer bytes to jwk/json (WebKit/Safari/IE11 quirk)
      if (jwk instanceof ArrayBuffer) {
        jwk = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(jwk)));
      }

      // map JWK parameters to BN
      key = {};
      key.n = new BN(util.b64_to_Uint8Array(jwk.n));
      key.e = E;
      key.d = new BN(util.b64_to_Uint8Array(jwk.d));
      key.p = new BN(util.b64_to_Uint8Array(jwk.p));
      key.q = new BN(util.b64_to_Uint8Array(jwk.q));
      key.u = key.p.invm(key.q);
      return key;
    }

    // RSA keygen fallback using 40 iterations of the Miller-Rabin test
    // See https://stackoverflow.com/a/6330138 for justification
    // Also see section C.3 here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST
    let p = await prime.randomProbablePrime(B - (B >> 1), E, 40);
    let q = await prime.randomProbablePrime(B >> 1, E, 40);

    if (p.cmp(q) < 0) {
      [p, q] = [q, p];
    }

    const phi = p.subn(1).mul(q.subn(1));
    return {
      n: p.mul(q),
      e: E,
      d: E.invm(phi),
      p: p,
      q: q,
      // dp: d.mod(p.subn(1)),
      // dq: d.mod(q.subn(1)),
      u: p.invm(q)
    };
  }
async function(B, E) {
    let key;
    E = new BN(E, 16);
    const webCrypto = util.getWebCryptoAll();

    // Native RSA keygen using Web Crypto
    if (webCrypto) {
      let keyPair;
      let keyGenOpt;
      if ((window.crypto && window.crypto.subtle) || window.msCrypto) {
        // current standard spec
        keyGenOpt = {
          name: 'RSASSA-PKCS1-v1_5',
          modulusLength: B, // the specified keysize in bits
          publicExponent: E.toArrayLike(Uint8Array), // take three bytes (max 65537) for exponent
          hash: {
            name: 'SHA-1' // not required for actual RSA keys, but for crypto api 'sign' and 'verify'
          }
        };
        keyPair = webCrypto.generateKey(keyGenOpt, true, ['sign', 'verify']);
        keyPair = await promisifyIE11Op(keyPair, 'Error generating RSA key pair.');
      } else if (window.crypto && window.crypto.webkitSubtle) {
        // outdated spec implemented by old Webkit
        keyGenOpt = {
          name: 'RSA-OAEP',
          modulusLength: B, // the specified keysize in bits
          publicExponent: E.toArrayLike(Uint8Array), // take three bytes (max 65537) for exponent
          hash: {
            name: 'SHA-1' // not required for actual RSA keys, but for crypto api 'sign' and 'verify'
          }
        };
        keyPair = await webCrypto.generateKey(keyGenOpt, true, ['encrypt', 'decrypt']);
      } else {
        throw new Error('Unknown WebCrypto implementation');
      }

      // export the generated keys as JsonWebKey (JWK)
      // https://tools.ietf.org/html/draft-ietf-jose-json-web-key-33
      let jwk = webCrypto.exportKey('jwk', keyPair.privateKey);
      jwk = await promisifyIE11Op(jwk, 'Error exporting RSA key pair.');

      // parse raw ArrayBuffer bytes to jwk/json (WebKit/Safari/IE11 quirk)
      if (jwk instanceof ArrayBuffer) {
        jwk = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(jwk)));
      }

      // map JWK parameters to BN
      key = {};
      key.n = new BN(util.b64_to_Uint8Array(jwk.n));
      key.e = E;
      key.d = new BN(util.b64_to_Uint8Array(jwk.d));
      key.p = new BN(util.b64_to_Uint8Array(jwk.p));
      key.q = new BN(util.b64_to_Uint8Array(jwk.q));
      key.u = key.p.invm(key.q);
      return key;
    }

    // RSA keygen fallback using 40 iterations of the Miller-Rabin test
    // See https://stackoverflow.com/a/6330138 for justification
    // Also see section C.3 here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST
    let p = await prime.randomProbablePrime(B - (B >> 1), E, 40);
    let q = await prime.randomProbablePrime(B >> 1, E, 40);

    if (p.cmp(q) < 0) {
      [p, q] = [q, p];
    }

    const phi = p.subn(1).mul(q.subn(1));
    return {
      n: p.mul(q),
      e: E,
      d: E.invm(phi),
      p: p,
      q: q,
      // dp: d.mod(p.subn(1)),
      // dq: d.mod(q.subn(1)),
      u: p.invm(q)
    };
  }
async function ( B , E ) { let key ; E = new BN ( E , 16 ) ; const webCrypto = util . getWebCryptoAll ( ) ; // Native RSA keygen using Web Crypto if ( webCrypto ) { let keyPair ; let keyGenOpt ; if ( ( window . crypto && window . crypto . subtle ) || window . msCrypto ) { // current standard spec keyGenOpt = { name : 'RSASSA-PKCS1-v1_5' , modulusLength : B , // the specified keysize in bits publicExponent : E . toArrayLike ( Uint8Array ) , // take three bytes (max 65537) for exponent hash : { name : 'SHA-1' // not required for actual RSA keys, but for crypto api 'sign' and 'verify' } } ; keyPair = webCrypto . generateKey ( keyGenOpt , true , [ 'sign' , 'verify' ] ) ; keyPair = await promisifyIE11Op ( keyPair , 'Error generating RSA key pair.' ) ; } else if ( window . crypto && window . crypto . webkitSubtle ) { // outdated spec implemented by old Webkit keyGenOpt = { name : 'RSA-OAEP' , modulusLength : B , // the specified keysize in bits publicExponent : E . toArrayLike ( Uint8Array ) , // take three bytes (max 65537) for exponent hash : { name : 'SHA-1' // not required for actual RSA keys, but for crypto api 'sign' and 'verify' } } ; keyPair = await webCrypto . generateKey ( keyGenOpt , true , [ 'encrypt' , 'decrypt' ] ) ; } else { throw new Error ( 'Unknown WebCrypto implementation' ) ; } // export the generated keys as JsonWebKey (JWK) // https://tools.ietf.org/html/draft-ietf-jose-json-web-key-33 let jwk = webCrypto . exportKey ( 'jwk' , keyPair . privateKey ) ; jwk = await promisifyIE11Op ( jwk , 'Error exporting RSA key pair.' ) ; // parse raw ArrayBuffer bytes to jwk/json (WebKit/Safari/IE11 quirk) if ( jwk instanceof ArrayBuffer ) { jwk = JSON . parse ( String . fromCharCode . apply ( null , new Uint8Array ( jwk ) ) ) ; } // map JWK parameters to BN key = { } ; key . n = new BN ( util . b64_to_Uint8Array ( jwk . n ) ) ; key . e = E ; key . d = new BN ( util . b64_to_Uint8Array ( jwk . d ) ) ; key . p = new BN ( util . b64_to_Uint8Array ( jwk . p ) ) ; key . q = new BN ( util . b64_to_Uint8Array ( jwk . q ) ) ; key . u = key . p . invm ( key . q ) ; return key ; } // RSA keygen fallback using 40 iterations of the Miller-Rabin test // See https://stackoverflow.com/a/6330138 for justification // Also see section C.3 here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST let p = await prime . randomProbablePrime ( B - ( B >> 1 ) , E , 40 ) ; let q = await prime . randomProbablePrime ( B >> 1 , E , 40 ) ; if ( p . cmp ( q ) < 0 ) { [ p , q ] = [ q , p ] ; } const phi = p . subn ( 1 ) . mul ( q . subn ( 1 ) ) ; return { n : p . mul ( q ) , e : E , d : E . invm ( phi ) , p : p , q : q , // dp: d.mod(p.subn(1)), // dq: d.mod(q.subn(1)), u : p . invm ( q ) } ; }
Generate a new random private key B bits long with public exponent E.

When possible, webCrypto is used. Otherwise, primes are generated using
40 rounds of the Miller-Rabin probabilistic random prime generation algorithm.
@see module:crypto/public_key/prime
@param {Integer} B RSA bit length
@param {String}  E RSA public exponent in hex string
@returns {{n: BN, e: BN, d: BN,
p: BN, q: BN, u: BN}} RSA public modulus, RSA public exponent, RSA private exponent,
RSA private prime p, RSA private prime q, u = q ** -1 mod p
@async
Generate a new random private key B bits long with public exponent E .