Deriving an RSA Public Key from a Private Key Using the Web Crypto API
While tools such as OpenSSL or Node.js provide methods to derive the public key from the private key:
- openssl:
openssl rsa -pubout -in private.pem -out public.pem
- node.js:
crypto.createPublicKey(privateKey)
https://nodejs.org/api/crypto.html#cryptocreatepublickeykey
The Web Crypto API does not include a direct method to derive an RSA public key from a private key.
However, you can achieve this by exporting the private key in JSON Web Key (JWK) format, extracting the modulus (n
) and public exponent (e
), and re-importing them as a public key:
See RFC 8017 (PKCS #1 v2.2) - RSA Public Key for more information on the RSA public key format.
/**
* Derive the public key from a private key in PEM format using the Web Crypto API.
* @param {string} privateKeyPem - The private key in PEM format.
* @return {Promise<CryptoKey>} - The public key as a CryptoKey.
* @see https://developer.mozilla.org/de/docs/Web/API/CryptoKey
*/
async function publicKeyFromPrivateKey(privateKeyPem) {
const base64 = pemToBase64(privateKeyPem); // remove PEM headers, remove newlines
const keyData = base64ToUint8Array(base64);
// Import the private key
// RSASSA-PKCS1-v1_5 refers to the RSA signature algorithm defined in rfc8017 https://www.rfc-editor.org/rfc/rfc8017#section-8.2
const rsaParams = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" };
const privateKey = await crypto.subtle.importKey("pkcs8", keyData, rsaParams, true, ["sign"]);
// Export the private key in JWK format
const privateKeyJwk = await crypto.subtle.exportKey("jwk", privateKey);
// Extract the modulus and public exponent from the private JWK
const { n, e } = privateKeyJwk;
// Create a new JWK with the public components
const publicKeyJwk = { kty: "RSA", e, n };
// Re-import the public key from our generated public JWK object
return crypto.subtle.importKey("jwk", publicKeyJwk, rsaParams, true, ["verify"]);
}
- Convert the PEM to Base64 and then to a
Uint8Array
. - Import the private key using
importKey
. - Export the key in JWK format, revealing the public components.
- Create a new JWK with
n
ande
, then import it as a public key.
You can find the full example on GitHub: https://gist.github.com/PutziSan/99a1aaede16c3f223fd59ae6d47a0d5e
Interactive Example
Below is an interactive example to derive the public key from a private key using the Web Crypto API directly in the browser (no server-side processing required, your private key stays private):
Generated Public Key in PEM format: