如何在NodeJS/Typescript中将JWK转换为PEM

vmdwslir  于 2023-01-12  发布在  Node.js
关注(0)|答案(1)|浏览(325)

我想从jwk端点下载公钥,并将其转换为jwtsing函数所需的pem

export type Secret =
    | string
    | Buffer
    | { key: string | Buffer; passphrase: string };

jwk可以使用subtlecrypto导入为JsonWebKey类型的webKey,并返回为CryptoKey

const pubKey = await subtle.importKey(
    "jwk",
    webKey,
    { hash: 'SHA-256', name: 'RSA-OAEP' },
    true,
    []
  );

CryptoKey可与subtle.exportKey一起导出,但结果在ByteArray中,并将其转换为pem(1.将字节转换为字符,然后2.转换为base64),然后将其添加到-----BEGIN PUBLIC KEY-----(带信封,每64个字符添加一行),生成无效密钥

/**
 * Exports the given key into the specified format, if supported.
 *
 * If the `<CryptoKey>` is not extractable, the returned promise will reject.
 *
 * When `format` is either `'pkcs8'` or `'spki'` and the export is successful,
 * the returned promise will be resolved with an `<ArrayBuffer>` containing the exported key data.
 *
 * When `format` is `'jwk'` and the export is successful, the returned promise will be resolved with a
 * JavaScript object conforming to the {@link https://tools.ietf.org/html/rfc7517 JSON Web Key} specification.
 * @param format Must be one of `'raw'`, `'pkcs8'`, `'spki'`, or `'jwk'`.
 * @returns `<Promise>` containing `<ArrayBuffer>`.
 * @since v15.0.0
 */
exportKey(format: 'jwk', key: CryptoKey): Promise<JsonWebKey>;
exportKey(format: Exclude<KeyFormat, 'jwk'>, key: CryptoKey): Promise<ArrayBuffer>;

此外,发布密钥只能导出到spkijwk,而raw不受支持。
问题是如何尽可能简单地将jwk转换为pem?!

jjhzyzn0

jjhzyzn01#

技巧是用static from(key: webcrypto.CryptoKey): KeyObject;CryptoKey转换为KeyObject,然后使用KeyObject的成员export(options: KeyExportOptions<'pem'>): string | Buffer;
函数将为

export async function jwkToPem(webKey: JsonWebKey): Promise<string> {
  const cryptoKey = await subtle.importKey(
    "jwk",
    webKey,
    { hash: 'SHA-256', name: 'RSA-OAEP' },
    true,
    []
  );

  return KeyObject.from(cryptoKey).export({ format: "pem", type: "pkcs1"}).toString();
}

托帕科的建议
使用createPublicKey会更容易,因为createPublicKey接受JsonWebKeyInput并生成可以轻松导出的KeyObject

/**
     * Creates and returns a new key object containing a public key. If `key` is a
     * string or `Buffer`, `format` is assumed to be `'pem'`; if `key` is a `KeyObject`with type `'private'`, the public key is derived from the given private key;
     * otherwise, `key` must be an object with the properties described above.
     *
     * If the format is `'pem'`, the `'key'` may also be an X.509 certificate.
     *
     * Because public keys can be derived from private keys, a private key may be
     * passed instead of a public key. In that case, this function behaves as if {@link createPrivateKey} had been called, except that the type of the
     * returned `KeyObject` will be `'public'` and that the private key cannot be
     * extracted from the returned `KeyObject`. Similarly, if a `KeyObject` with type`'private'` is given, a new `KeyObject` with type `'public'` will be returned
     * and it will be impossible to extract the private key from the returned object.
     * @since v11.6.0
     */
    function createPublicKey(key: PublicKeyInput | string | Buffer | KeyObject | JsonWebKeyInput): KeyObject;

那么

export async function jwkToPem(webKey: JsonWebKey): Promise<string> {
  const pubKey: KeyObject = createPublicKey({
    key: webKey,
    format: 'jwk'
  });

  return pubKey.export({ format: "pem", type: "pkcs1"}).toString();
}

相关问题