From f4741ef8dfa4d8a5fe4bd1501869073b4c192ec4 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Fri, 1 Aug 2025 22:09:12 +0200 Subject: [PATCH] crypto: add subtle.getPublicKey() utility function in Web Cryptography PR-URL: https://github.com/nodejs/node/pull/59365 Reviewed-By: James M Snell Reviewed-By: Ethan Arrowood Reviewed-By: Yagiz Nizipli Reviewed-By: Joyee Cheung --- doc/api/webcrypto.md | 78 +++++++++++-------- lib/internal/crypto/webcrypto.js | 55 +++++++++++++ .../webcrypto/supports-modern-algorithms.mjs | 16 ++++ test/parallel/test-webcrypto-constructors.js | 7 ++ .../test-webcrypto-get-public-key.mjs | 51 ++++++++++++ 5 files changed, 176 insertions(+), 31 deletions(-) create mode 100644 test/parallel/test-webcrypto-get-public-key.mjs diff --git a/doc/api/webcrypto.md b/doc/api/webcrypto.md index 4607d71f57..1b109f38d2 100644 --- a/doc/api/webcrypto.md +++ b/doc/api/webcrypto.md @@ -115,6 +115,7 @@ Key Formats: Methods: +* [`subtle.getPublicKey()`][] * [`SubtleCrypto.supports()`][] ## Secure Curves in the Web Cryptography API @@ -478,36 +479,36 @@ const decrypted = new TextDecoder().decode(await crypto.subtle.decrypt( The table details the algorithms supported by the Node.js Web Crypto API implementation and the APIs supported for each: -| Algorithm | `generateKey` | `exportKey` | `importKey` | `encrypt` | `decrypt` | `wrapKey` | `unwrapKey` | `deriveBits` | `deriveKey` | `sign` | `verify` | `digest` | -| ---------------------------- | ------------- | ----------- | ----------- | --------- | --------- | --------- | ----------- | ------------ | ----------- | ------ | -------- | -------- | -| `'AES-CBC'` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | | | | -| `'AES-CTR'` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | | | | -| `'AES-GCM'` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | | | | -| `'AES-KW'` | ✔ | ✔ | ✔ | | | ✔ | ✔ | | | | | | -| `'cSHAKE128'`[^modern-algos] | | | | | | | | | | | | ✔ | -| `'cSHAKE256'`[^modern-algos] | | | | | | | | | | | | ✔ | -| `'ECDH'` | ✔ | ✔ | ✔ | | | | | ✔ | ✔ | | | | -| `'ECDSA'` | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | -| `'Ed25519'` | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | -| `'Ed448'`[^secure-curves] | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | -| `'HKDF'` | | ✔ | ✔ | | | | | ✔ | ✔ | | | | -| `'HMAC'` | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | -| `'ML-DSA-44'`[^modern-algos] | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | -| `'ML-DSA-65'`[^modern-algos] | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | -| `'ML-DSA-87'`[^modern-algos] | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | -| `'PBKDF2'` | | ✔ | ✔ | | | | | ✔ | ✔ | | | | -| `'RSA-OAEP'` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | | | | -| `'RSA-PSS'` | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | -| `'RSASSA-PKCS1-v1_5'` | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | -| `'SHA-1'` | | | | | | | | | | | | ✔ | -| `'SHA-256'` | | | | | | | | | | | | ✔ | -| `'SHA-384'` | | | | | | | | | | | | ✔ | -| `'SHA-512'` | | | | | | | | | | | | ✔ | -| `'SHA3-256'`[^modern-algos] | | | | | | | | | | | | ✔ | -| `'SHA3-384'`[^modern-algos] | | | | | | | | | | | | ✔ | -| `'SHA3-512'`[^modern-algos] | | | | | | | | | | | | ✔ | -| `'X25519'` | ✔ | ✔ | ✔ | | | | | ✔ | ✔ | | | | -| `'X448'`[^secure-curves] | ✔ | ✔ | ✔ | | | | | ✔ | ✔ | | | | +| Algorithm | `generateKey` | `exportKey` | `importKey` | `encrypt` | `decrypt` | `wrapKey` | `unwrapKey` | `deriveBits` | `deriveKey` | `sign` | `verify` | `digest` | `getPublicKey` | +| ---------------------------- | ------------- | ----------- | ----------- | --------- | --------- | --------- | ----------- | ------------ | ----------- | ------ | -------- | -------- | -------------- | +| `'AES-CBC'` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | | | | | +| `'AES-CTR'` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | | | | | +| `'AES-GCM'` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | | | | | +| `'AES-KW'` | ✔ | ✔ | ✔ | | | ✔ | ✔ | | | | | | | +| `'cSHAKE128'`[^modern-algos] | | | | | | | | | | | | ✔ | | +| `'cSHAKE256'`[^modern-algos] | | | | | | | | | | | | ✔ | | +| `'ECDH'` | ✔ | ✔ | ✔ | | | | | ✔ | ✔ | | | | ✔ | +| `'ECDSA'` | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | ✔ | +| `'Ed25519'` | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | ✔ | +| `'Ed448'`[^secure-curves] | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | ✔ | +| `'HKDF'` | | ✔ | ✔ | | | | | ✔ | ✔ | | | | | +| `'HMAC'` | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | | +| `'ML-DSA-44'`[^modern-algos] | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | ✔ | +| `'ML-DSA-65'`[^modern-algos] | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | ✔ | +| `'ML-DSA-87'`[^modern-algos] | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | ✔ | +| `'PBKDF2'` | | ✔ | ✔ | | | | | ✔ | ✔ | | | | | +| `'RSA-OAEP'` | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | | | | ✔ | +| `'RSA-PSS'` | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | ✔ | +| `'RSASSA-PKCS1-v1_5'` | ✔ | ✔ | ✔ | | | | | | | ✔ | ✔ | | ✔ | +| `'SHA-1'` | | | | | | | | | | | | ✔ | | +| `'SHA-256'` | | | | | | | | | | | | ✔ | | +| `'SHA-384'` | | | | | | | | | | | | ✔ | | +| `'SHA-512'` | | | | | | | | | | | | ✔ | | +| `'SHA3-256'`[^modern-algos] | | | | | | | | | | | | ✔ | | +| `'SHA3-384'`[^modern-algos] | | | | | | | | | | | | ✔ | | +| `'SHA3-512'`[^modern-algos] | | | | | | | | | | | | ✔ | | +| `'X25519'` | ✔ | ✔ | ✔ | | | | | ✔ | ✔ | | | | ✔ | +| `'X448'`[^secure-curves] | ✔ | ✔ | ✔ | | | | | ✔ | ✔ | | | | ✔ | ## Class: `Crypto` @@ -692,7 +693,7 @@ added: REPLACEME -* `operation` {string} "encrypt", "decrypt", "sign", "verify", "digest", "generateKey", "deriveKey", "deriveBits", "importKey", "exportKey", "wrapKey", or "unwrapKey" +* `operation` {string} "encrypt", "decrypt", "sign", "verify", "digest", "generateKey", "deriveKey", "deriveBits", "importKey", "exportKey", "getPublicKey", "wrapKey", or "unwrapKey" * `algorithm` {string|Algorithm} * `lengthOrAdditionalAlgorithm` {null|number|string|Algorithm|undefined} Depending on the operation this is either ignored, the value of the length argument when operation is "deriveBits", the algorithm of key to be derived when operation is "deriveKey", the algorithm of key to be exported before wrapping when operation is "wrapKey", or the algorithm of key to be imported after unwrapping when operation is "unwrapKey". **Default:** `null` when operation is "deriveBits", `undefined` otherwise. * Returns: {boolean} Indicating whether the implementation supports the given operation @@ -926,6 +927,20 @@ specification. | `'RSA-PSS'` | ✔ | ✔ | ✔ | | | | | | `'RSASSA-PKCS1-v1_5'` | ✔ | ✔ | ✔ | | | | | +### `subtle.getPublicKey(key, keyUsages)` + + + +> Stability: 1.1 - Active development + +* `key` {CryptoKey} A private key from which to derive the corresponding public key. +* `keyUsages` {string\[]} See [Key usages][]. +* Returns: {Promise} Fulfills with a {CryptoKey} upon success. + +Derives the public key from a given private key. + ### `subtle.generateKey(algorithm, extractable, keyUsages)`