diff --git a/src/runtime/browser/webcrypto.ts b/src/runtime/browser/webcrypto.ts index 1703f367..1ec3cb91 100644 --- a/src/runtime/browser/webcrypto.ts +++ b/src/runtime/browser/webcrypto.ts @@ -3,5 +3,8 @@ import globalThis from './global.js' export default globalThis.crypto export function isCryptoKey(key: unknown): key is CryptoKey { - return key instanceof globalThis.CryptoKey + if (typeof globalThis.CryptoKey === 'undefined') { + return false + } + return key != null && key instanceof globalThis.CryptoKey } diff --git a/src/runtime/node/aeskw.ts b/src/runtime/node/aeskw.ts index 2c47ce92..174629fb 100644 --- a/src/runtime/node/aeskw.ts +++ b/src/runtime/node/aeskw.ts @@ -4,6 +4,7 @@ import type { AesKwUnwrapFunction, AesKwWrapFunction } from '../interfaces.d' import { concat } from '../../lib/buffer_utils.js' import getSecretKey from './secret_key.js' import { isCryptoKey, getKeyObject } from './webcrypto.js' +import isKeyObject from './is_key_object.js' function checkKeySize(key: KeyObject, alg: string) { if (key.symmetricKeySize! << 3 !== parseInt(alg.substr(1, 3), 10)) { @@ -12,7 +13,7 @@ function checkKeySize(key: KeyObject, alg: string) { } function ensureKeyObject(key: unknown, alg: string, usage: KeyUsage) { - if (key instanceof KeyObject) { + if (isKeyObject(key)) { return key } if (key instanceof Uint8Array) { diff --git a/src/runtime/node/check_cek_length.ts b/src/runtime/node/check_cek_length.ts index eb3a2a3f..67984565 100644 --- a/src/runtime/node/check_cek_length.ts +++ b/src/runtime/node/check_cek_length.ts @@ -1,5 +1,6 @@ import { KeyObject } from 'crypto' import { JWEInvalid, JOSENotSupported } from '../../util/errors.js' +import isKeyObject from './is_key_object.js' const checkCekLength = (enc: string, cek: KeyObject | Uint8Array) => { let expected: number @@ -27,7 +28,7 @@ const checkCekLength = (enc: string, cek: KeyObject | Uint8Array) => { return } - if (cek instanceof KeyObject && cek.type === 'secret') { + if (isKeyObject(cek) && cek.type === 'secret') { if (cek.symmetricKeySize! << 3 !== expected) { throw new JWEInvalid('Invalid Content Encryption Key length') } diff --git a/src/runtime/node/decrypt.ts b/src/runtime/node/decrypt.ts index b1bd3826..1de23212 100644 --- a/src/runtime/node/decrypt.ts +++ b/src/runtime/node/decrypt.ts @@ -10,6 +10,7 @@ import timingSafeEqual from './timing_safe_equal.js' import cbcTag from './cbc_tag.js' import { isCryptoKey, getKeyObject } from './webcrypto.js' import type { KeyLike } from '../../types.d' +import isKeyObject from './is_key_object.js' async function cbcDecrypt( enc: string, @@ -21,7 +22,7 @@ async function cbcDecrypt( ) { const keySize = parseInt(enc.substr(1, 3), 10) - if (cek instanceof KeyObject) { + if (isKeyObject(cek)) { // eslint-disable-next-line no-param-reassign cek = cek.export() } @@ -99,7 +100,7 @@ const decrypt: DecryptFunction = async ( if (isCryptoKey(cek)) { // eslint-disable-next-line no-param-reassign key = getKeyObject(cek, enc, new Set(['decrypt'])) - } else if (cek instanceof Uint8Array || cek instanceof KeyObject) { + } else if (cek instanceof Uint8Array || isKeyObject(cek)) { key = cek } else { throw new TypeError('invalid key input') diff --git a/src/runtime/node/ecdhes.ts b/src/runtime/node/ecdhes.ts index c05c6ea5..352a3bec 100644 --- a/src/runtime/node/ecdhes.ts +++ b/src/runtime/node/ecdhes.ts @@ -1,4 +1,4 @@ -import { KeyObject, diffieHellman, generateKeyPair as generateKeyPairCb } from 'crypto' +import { diffieHellman, generateKeyPair as generateKeyPairCb } from 'crypto' import { promisify } from 'util' import type { @@ -11,6 +11,7 @@ import { encoder, concat, uint32be, lengthAndInput, concatKdf } from '../../lib/ import digest from './digest.js' import { JOSENotSupported } from '../../util/errors.js' import { isCryptoKey, getKeyObject } from './webcrypto.js' +import isKeyObject from './is_key_object.js' const generateKeyPair = promisify(generateKeyPairCb) @@ -33,7 +34,7 @@ export const deriveKey: EcdhESDeriveKeyFunction = async ( // eslint-disable-next-line no-param-reassign publicKey = getKeyObject(publicKey, 'ECDH-ES') } - if (!(publicKey instanceof KeyObject)) { + if (!isKeyObject(publicKey)) { throw new TypeError('invalid key input') } @@ -41,7 +42,7 @@ export const deriveKey: EcdhESDeriveKeyFunction = async ( // eslint-disable-next-line no-param-reassign privateKey = getKeyObject(privateKey, 'ECDH-ES', new Set(['deriveBits', 'deriveKey'])) } - if (!(privateKey instanceof KeyObject)) { + if (!isKeyObject(privateKey)) { throw new TypeError('invalid key input') } @@ -54,7 +55,7 @@ export const generateEpk: GenerateEpkFunction = async (key: unknown) => { // eslint-disable-next-line no-param-reassign key = getKeyObject(key) } - if (!(key instanceof KeyObject)) { + if (!isKeyObject(key)) { throw new TypeError('invalid key input') } diff --git a/src/runtime/node/encrypt.ts b/src/runtime/node/encrypt.ts index f2a81218..516a67c0 100644 --- a/src/runtime/node/encrypt.ts +++ b/src/runtime/node/encrypt.ts @@ -8,6 +8,7 @@ import { concat } from '../../lib/buffer_utils.js' import cbcTag from './cbc_tag.js' import type { KeyLike } from '../../types.d' import { isCryptoKey, getKeyObject } from './webcrypto.js' +import isKeyObject from './is_key_object.js' async function cbcEncrypt( enc: string, @@ -18,7 +19,7 @@ async function cbcEncrypt( ) { const keySize = parseInt(enc.substr(1, 3), 10) - if (cek instanceof KeyObject) { + if (isKeyObject(cek)) { // eslint-disable-next-line no-param-reassign cek = cek.export() } @@ -67,7 +68,7 @@ const encrypt: EncryptFunction = async ( if (isCryptoKey(cek)) { // eslint-disable-next-line no-param-reassign key = getKeyObject(cek, enc, new Set(['encrypt'])) - } else if (cek instanceof Uint8Array || cek instanceof KeyObject) { + } else if (cek instanceof Uint8Array || isKeyObject(cek)) { key = cek } else { throw new TypeError('invalid key input') diff --git a/src/runtime/node/get_named_curve.ts b/src/runtime/node/get_named_curve.ts index 8add1640..d25377d5 100644 --- a/src/runtime/node/get_named_curve.ts +++ b/src/runtime/node/get_named_curve.ts @@ -1,6 +1,7 @@ import { KeyObject, createPublicKey } from 'crypto' import { JOSENotSupported } from '../../util/errors.js' import { isCryptoKey, getKeyObject } from './webcrypto.js' +import isKeyObject from './is_key_object.js' const p256 = Buffer.from([42, 134, 72, 206, 61, 3, 1, 7]) const p384 = Buffer.from([43, 129, 4, 0, 34]) @@ -29,7 +30,7 @@ const getNamedCurve = (key: unknown, raw?: boolean): string => { // eslint-disable-next-line no-param-reassign key = getKeyObject(key) } - if (!(key instanceof KeyObject)) { + if (!isKeyObject(key)) { throw new TypeError('invalid key input') } diff --git a/src/runtime/node/is_key_object.ts b/src/runtime/node/is_key_object.ts new file mode 100644 index 00000000..536791e2 --- /dev/null +++ b/src/runtime/node/is_key_object.ts @@ -0,0 +1,5 @@ +import { KeyObject } from 'crypto' + +export default function isKeyObject(obj: unknown): obj is KeyObject { + return obj != null && obj instanceof KeyObject +} diff --git a/src/runtime/node/key_to_jwk.ts b/src/runtime/node/key_to_jwk.ts index f34a3db3..554edb33 100644 --- a/src/runtime/node/key_to_jwk.ts +++ b/src/runtime/node/key_to_jwk.ts @@ -6,6 +6,7 @@ import Asn1SequenceDecoder from './asn1_sequence_decoder.js' import { JOSENotSupported } from '../../util/errors.js' import getNamedCurve from './get_named_curve.js' import { isCryptoKey, getKeyObject } from './webcrypto.js' +import isKeyObject from './is_key_object.js' const [major, minor] = process.version .substr(1) @@ -21,7 +22,7 @@ const keyToJWK: JWKConvertFunction = (key: unknown): JWK => { throw new TypeError('CryptoKey is not extractable') } keyObject = getKeyObject(key) - } else if (key instanceof KeyObject) { + } else if (isKeyObject(key)) { keyObject = key } else { throw new TypeError('invalid key input') diff --git a/src/runtime/node/pbes2kw.ts b/src/runtime/node/pbes2kw.ts index a6bab7d0..5286b578 100644 --- a/src/runtime/node/pbes2kw.ts +++ b/src/runtime/node/pbes2kw.ts @@ -1,5 +1,5 @@ import { promisify } from 'util' -import { KeyObject, pbkdf2 as pbkdf2cb } from 'crypto' +import { pbkdf2 as pbkdf2cb } from 'crypto' import type { Pbes2KWDecryptFunction, Pbes2KWEncryptFunction } from '../interfaces.d' import random from './random.js' import { p2s as concatSalt } from '../../lib/buffer_utils.js' @@ -7,11 +7,12 @@ import { encode as base64url } from './base64url.js' import { wrap, unwrap } from './aeskw.js' import checkP2s from '../../lib/check_p2s.js' import { isCryptoKey, getKeyObject } from './webcrypto.js' +import isKeyObject from './is_key_object.js' const pbkdf2 = promisify(pbkdf2cb) function getPassword(key: unknown, alg: string) { - if (key instanceof KeyObject) { + if (isKeyObject(key)) { return key.export() } if (key instanceof Uint8Array) { diff --git a/src/runtime/node/rsaes.ts b/src/runtime/node/rsaes.ts index 8f1795ab..d6d739d6 100644 --- a/src/runtime/node/rsaes.ts +++ b/src/runtime/node/rsaes.ts @@ -2,6 +2,7 @@ import { KeyObject, publicEncrypt, constants, privateDecrypt } from 'crypto' import type { RsaEsDecryptFunction, RsaEsEncryptFunction } from '../interfaces.d' import checkModulusLength from './check_modulus_length.js' import { isCryptoKey, getKeyObject } from './webcrypto.js' +import isKeyObject from './is_key_object.js' const checkKey = (key: KeyObject, alg: string) => { if (key.type === 'secret' || key.asymmetricKeyType !== 'rsa') { @@ -40,7 +41,7 @@ const resolveOaepHash = (alg: string) => { } function ensureKeyObject(key: unknown, alg: string, ...usages: KeyUsage[]) { - if (key instanceof KeyObject) { + if (isKeyObject(key)) { return key } if (isCryptoKey(key)) { diff --git a/src/runtime/node/webcrypto.ts b/src/runtime/node/webcrypto.ts index b691fc65..80597003 100644 --- a/src/runtime/node/webcrypto.ts +++ b/src/runtime/node/webcrypto.ts @@ -7,7 +7,7 @@ export default webcrypto export function isCryptoKey(key: unknown): key is CryptoKey { if (webcrypto !== undefined) { // @ts-expect-error - return key instanceof webcrypto.CryptoKey + return key != null && key instanceof webcrypto.CryptoKey } return false