7

I am creating an ACME client and I need to find the modulus and exponent of my RSA public key, which I generate using the following code:

crypto.generateKeyPairSync('rsa', {
    modulusLength: 4096,
    publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
    },
    privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem'
    }
});

I need the modulus and exponent, so that I can use them in the JWK section of my JWS:

alg: 'RS256',
jwk: {
    kty: 'RSA',
    e: '...',
    n: '...'
},
nonce,
url: directory.newAccount

I have managed to decode the public key from base64 to hex using the following line, but I am not sure what to do next:

Buffer.from(publicKey, 'base64').toString('hex');

How do I find the modulus and exponent of an RSA public key in Node.js?



EDIT 1

I have discovered that Node.js uses the public exponent 65537 by default: Node.js documentation.

Community
  • 1
  • 1
Daemon Beast
  • 2,794
  • 3
  • 12
  • 29

3 Answers3

5

It's easy as a piece of cake; it doesn't require 3rd party libraries

import { createPublicKey } from 'crypto'

const pemPublicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAphRAj+tRfbrYwnSFbWrj
...
vQIDAQAB
-----END PUBLIC KEY-----
`
const publicKey = createPublicKey(pemPublicKey)
console.log(publicKey.export({ format: 'jwk' }))

it will return object:

{
  kty: 'RSA',
  n: [modulus string],
  e: [exponent string]
}
Roman Podlinov
  • 23,806
  • 7
  • 41
  • 60
  • 2
    Just note that export support jwk format from NodeJS version v15.9.0. but indeed this answer helped me a great deal. – Mercury May 25 '22 at 06:36
2

Expanding the comment given by @Topaco, use the library pem-jwk like this:

const pem2jwk = require('pem-jwk').pem2jwk

console.log(pem2jwk(pemPublicKey));
OUTPUT:
{
  kty: '...',
  n: '...',
  e: '...'
}

console.log(pem2jwk(pemPrivateKey));
OUTPUT:
{
  kty: '...',
  n: '...',
  e: '...',
  d: '...',
  p: '...',
  q: '...',
  dp: '...',
  dq: '...',
  qi: '...'
}

lmiguelmh
  • 3,074
  • 1
  • 37
  • 53
0

There are libraries written for both browser and node.js works very good. You can find them here.

Include the files and try this func,

function RSAModulusAndExponent(pubkey) {
        var unarmor = /-----BEGIN PUBLIC KEY-----([A-Za-z0-9+\/=\s]+)-----END PUBLIC KEY-----/;
         try{
            var pubkeyAsn1 = ASN1.decode(Base64.decode(unarmor.exec(pubkey)[1]));
            var modulusRaw = pubkeyAsn1.sub[1].sub[0].sub[0];
            var modulusStart = modulusRaw.header + modulusRaw.stream.pos + 1;
            var modulusEnd = modulusRaw.length + modulusRaw.stream.pos + modulusRaw.header;
            var modulusHex = modulusRaw.stream.hexDump(modulusStart, modulusEnd);
            var modulus = Hex.decode(modulusHex);
            var exponentRaw = pubkeyAsn1.sub[1].sub[0].sub[1];
            var exponentStart = exponentRaw.header + exponentRaw.stream.pos;
            var exponentEnd = exponentRaw.length + exponentRaw.stream.pos + exponentRaw.header;
            var exponentHex = exponentRaw.stream.hexDump(exponentStart, exponentEnd);
            var exponent = Hex.decode(exponentHex);
            
            return { success:true, msg:{moduls: modulus, exponent: exponent}};
        }
        catch(err){ console.log(err)
            return { success:false, msg:"Failed validating RSA public key."};
        }
    }

There you have your modulus and exponent.

For public key validation on node, I would recommend
node-jose (or) NodeRSA

const key = new NodeRSA(pubKey);   

if(key.isPublic && !key.isEmpty() && key.getKeySize() > 0)
        return {error: false, msg : "RSA Public key validation success! (Reason, isPublic?"+key.isPublic()+", isEmpty?"+key.isEmpty()+", Key length : " + key.getKeySize()+" )"}
 else
        return {error: false, msg : "RSA Public key validation failed! (Reason, isPublic?"+key.isPublic()+", isEmpty?"+key.isEmpty()+", Key length : " + key.getKeySize()+" )"}

I just laid out an idea. There are other functions in the library which is sufficient enough to make sure the public key is okay.

Also, you have node on command line. you can see a raw format using openssl. see more here,OpenSSL Manual

openssl asn1parse -in your_public.key
Community
  • 1
  • 1
Arun Panneerselvam
  • 2,263
  • 1
  • 17
  • 24