UNPKG

@sphereon/ssi-sdk-ext.key-utils

Version:

Sphereon SSI-SDK plugin for key creation.

1,403 lines (1,397 loc) • 44.2 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // src/functions.ts import { randomBytes } from "@ethersproject/random"; import { bls12_381 } from "@noble/curves/bls12-381"; import { ed25519 } from "@noble/curves/ed25519"; import { p256 } from "@noble/curves/p256"; import { p384 } from "@noble/curves/p384"; import { p521 } from "@noble/curves/p521"; import { secp256k1 } from "@noble/curves/secp256k1"; import { sha256 as sha2562, sha384 as sha3842, sha512 as sha5122 } from "@noble/hashes/sha2"; import { cryptoSubtleImportRSAKey, generateRSAKeyAsPEM, hexToBase64, hexToPEM, PEMToJwk, privateKeyHexFromPEM } from "@sphereon/ssi-sdk-ext.x509-utils"; import { JoseCurve, JoseSignatureAlgorithm, JwkKeyType, Loggers } from "@sphereon/ssi-types"; import { generateKeyPair as generateSigningKeyPair } from "@stablelib/ed25519"; import debug from "debug"; import elliptic from "elliptic"; import * as rsa from "micro-rsa-dsa-dh/rsa.js"; import * as u8a2 from "uint8arrays"; // src/digest-methods.ts import { sha256 } from "@noble/hashes/sha256"; import { sha384, sha512 } from "@noble/hashes/sha512"; import * as u8a from "uint8arrays"; var { fromString, toString, SupportedEncodings } = u8a; var digestMethodParams = /* @__PURE__ */ __name((hashAlgorithm) => { if (hashAlgorithm === "SHA-256") { return { hashAlgorithm: "SHA-256", digestMethod: sha256DigestMethod, hash: sha256 }; } else if (hashAlgorithm === "SHA-384") { return { hashAlgorithm: "SHA-384", digestMethod: sha384DigestMethod, hash: sha384 }; } else { return { hashAlgorithm: "SHA-512", digestMethod: sha512DigestMethod, hash: sha512 }; } }, "digestMethodParams"); var shaHasher = /* @__PURE__ */ __name((input, alg) => { const hashAlgorithm = alg.includes("384") ? "SHA-384" : alg.includes("512") ? "SHA-512" : "SHA-256"; return digestMethodParams(hashAlgorithm).hash(typeof input === "string" ? fromString(input, "utf-8") : new Uint8Array(input)); }, "shaHasher"); var sha256DigestMethod = /* @__PURE__ */ __name((input, encoding = "base16") => { return toString(sha256(fromString(input, "utf-8")), encoding); }, "sha256DigestMethod"); var sha384DigestMethod = /* @__PURE__ */ __name((input, encoding = "base16") => { return toString(sha384(fromString(input, "utf-8")), encoding); }, "sha384DigestMethod"); var sha512DigestMethod = /* @__PURE__ */ __name((input, encoding = "base16") => { return toString(sha512(fromString(input, "utf-8")), encoding); }, "sha512DigestMethod"); // src/jwk-jcs.ts import { TextDecoder, TextEncoder } from "web-encoding"; var textEncoder = new TextEncoder(); var textDecoder = new TextDecoder(); function check(value, description, optional = false) { if (optional && !value) { return; } if (typeof value !== "string" || !value) { throw new Error(`${description} missing or invalid`); } } __name(check, "check"); function assertObject(value) { if (!value || typeof value !== "object") { throw new Error("Value must be an object"); } } __name(assertObject, "assertObject"); function validateJwk(jwk, opts) { assertObject(jwk); const { crvOptional = false } = opts ?? {}; check(jwk.kty, '"kty" (Key Type) Parameter', false); switch (jwk.kty) { /** * @see https://www.rfc-editor.org/rfc/rfc7518#section-6.2.1 */ case "EC": check(jwk.crv, '"crv" (Curve) Parameter', crvOptional); check(jwk.x, '"x" (X Coordinate) Parameter'); check(jwk.y, '"y" (Y Coordinate) Parameter'); break; /** * @see https://www.rfc-editor.org/rfc/rfc8037#section-2 */ case "OKP": check(jwk.crv, '"crv" (Subtype of Key Pair) Parameter', crvOptional); check(jwk.x, '"x" (Public Key) Parameter'); break; /** * @see https://www.rfc-editor.org/rfc/rfc7518#section-6.3.1 */ case "RSA": check(jwk.e, '"e" (Exponent) Parameter'); check(jwk.n, '"n" (Modulus) Parameter'); break; default: throw new Error('"kty" (Key Type) Parameter missing or unsupported'); } } __name(validateJwk, "validateJwk"); function minimalJwk(jwk) { switch (jwk.kty) { case "EC": return { ...jwk.crv && { crv: jwk.crv }, kty: jwk.kty, x: jwk.x, y: jwk.y }; case "OKP": return { ...jwk.crv && { crv: jwk.crv }, kty: jwk.kty, x: jwk.x }; case "RSA": return { e: jwk.e, kty: jwk.kty, n: jwk.n }; } throw Error(`Unsupported key type (kty) provided: ${jwk.kty}`); } __name(minimalJwk, "minimalJwk"); function jwkJcsEncode(jwk) { validateJwk(jwk); const strippedJwk = minimalJwk(jwk); return textEncoder.encode(jcsCanonicalize(strippedJwk)); } __name(jwkJcsEncode, "jwkJcsEncode"); function jwkJcsDecode(bytes) { const jwk = JSON.parse(textDecoder.decode(bytes)); validateJwk(jwk); if (JSON.stringify(jwk) !== jcsCanonicalize(minimalJwk(jwk))) { throw new Error("The JWK embedded in the DID is not correctly formatted"); } return jwk; } __name(jwkJcsDecode, "jwkJcsDecode"); function jcsCanonicalize(object) { let buffer = ""; serialize(object); return buffer; function serialize(object2) { if (object2 === null || typeof object2 !== "object" || object2.toJSON != null) { buffer += JSON.stringify(object2); } else if (Array.isArray(object2)) { buffer += "["; let next = false; object2.forEach((element) => { if (next) { buffer += ","; } next = true; serialize(element); }); buffer += "]"; } else { buffer += "{"; let next = false; Object.keys(object2).sort().forEach((property) => { if (next) { buffer += ","; } next = true; buffer += JSON.stringify(property); buffer += ":"; serialize(object2[property]); }); buffer += "}"; } } __name(serialize, "serialize"); } __name(jcsCanonicalize, "jcsCanonicalize"); // src/types/key-util-types.ts var JWK_JCS_PUB_NAME = "jwk_jcs-pub"; var JWK_JCS_PUB_PREFIX = 60241; var Key = /* @__PURE__ */ function(Key2) { Key2["Ed25519"] = "Ed25519"; Key2["Secp256k1"] = "Secp256k1"; Key2["Secp256r1"] = "Secp256r1"; return Key2; }({}); var JwkKeyUse = /* @__PURE__ */ function(JwkKeyUse2) { JwkKeyUse2["Encryption"] = "enc"; JwkKeyUse2["Signature"] = "sig"; return JwkKeyUse2; }({}); var SIG_KEY_ALGS = [ "ES256", "ES384", "ES512", "EdDSA", "ES256K", "Ed25519", "Secp256k1", "Secp256r1", "Bls12381G1", "Bls12381G2" ]; var ENC_KEY_ALGS = [ "X25519", "ECDH_ES_A256KW", "RSA_OAEP_256" ]; // src/functions.ts var { fromString: fromString2, toString: toString2 } = u8a2; var logger = Loggers.DEFAULT.get("sphereon:key-utils"); var getKms = /* @__PURE__ */ __name(async (context, kms) => { if (kms) { return kms; } if (!context.agent.availableMethods().includes("keyManagerGetDefaultKeyManagementSystem")) { throw Error("Cannot determine default KMS if not provided and a non Sphereon Key Manager is being used"); } return context.agent.keyManagerGetDefaultKeyManagementSystem(); }, "getKms"); var generatePrivateKeyHex = /* @__PURE__ */ __name(async (type) => { switch (type) { case "Ed25519": { const keyPairEd25519 = generateSigningKeyPair(); return toString2(keyPairEd25519.secretKey, "base16"); } // The Secp256 types use the same method to generate the key case "Secp256r1": case "Secp256k1": { const privateBytes = randomBytes(32); return toString2(privateBytes, "base16"); } case "RSA": { const pem = await generateRSAKeyAsPEM("RSA-PSS", "SHA-256", 2048); return privateKeyHexFromPEM(pem); } default: throw Error(`not_supported: Key type ${type} not yet supported for this did:jwk implementation`); } }, "generatePrivateKeyHex"); var keyMetaAlgorithmsFromKeyType = /* @__PURE__ */ __name((type) => { switch (type) { case "Ed25519": return [ "Ed25519", "EdDSA" ]; case "ES256K": case "Secp256k1": return [ "ES256K", "ES256K-R", "eth_signTransaction", "eth_signTypedData", "eth_signMessage", "eth_rawSign" ]; case "Secp256r1": return [ "ES256" ]; case "X25519": return [ "ECDH", "ECDH-ES", "ECDH-1PU" ]; case "RSA": return [ "RS256", "RS512", "PS256", "PS512" ]; } return [ type ]; }, "keyMetaAlgorithmsFromKeyType"); async function importProvidedOrGeneratedKey(args, context) { const type = args.options?.type ?? args.options?.key?.type ?? args.options?.keyType ?? "Secp256r1"; const key = args?.options?.key; if (args.options?.x509 && key) { key.meta = { ...key.meta, x509: { ...args.options.x509, ...key.meta?.x509 } }; } if (args.options && args.options?.use === JwkKeyUse.Encryption && !ENC_KEY_ALGS.includes(type)) { throw new Error(`${type} keys are not valid for encryption`); } let privateKeyHex = void 0; if (key) { privateKeyHex = key.privateKeyHex ?? key.meta?.x509?.privateKeyHex; if ((!privateKeyHex || privateKeyHex.trim() === "") && key?.meta?.x509?.privateKeyPEM) { privateKeyHex = privateKeyHexFromPEM(key.meta.x509.privateKeyPEM); } } if (privateKeyHex) { return context.agent.keyManagerImport({ ...key, kms: args.kms, type, privateKeyHex }); } return context.agent.keyManagerCreate({ type, kms: args.kms, meta: { ...key?.meta, algorithms: keyMetaAlgorithmsFromKeyType(type), keyAlias: args.alias } }); } __name(importProvidedOrGeneratedKey, "importProvidedOrGeneratedKey"); var calculateJwkThumbprintForKey = /* @__PURE__ */ __name((args) => { const { key } = args; const jwk = key.publicKeyHex ? toJwk(key.publicKeyHex, key.type, { key, isPrivateKey: false }) : "privateKeyHex" in key && key.privateKeyHex ? toJwk(key.privateKeyHex, key.type, { isPrivateKey: true }) : void 0; if (!jwk) { throw Error(`Could not determine jwk from key ${key.kid}`); } return calculateJwkThumbprint({ jwk, digestAlgorithm: args.digestAlgorithm }); }, "calculateJwkThumbprintForKey"); var assertJwkClaimPresent = /* @__PURE__ */ __name((value, description) => { if (typeof value !== "string" || !value) { throw new Error(`${description} missing or invalid`); } }, "assertJwkClaimPresent"); var toBase64url = /* @__PURE__ */ __name((input) => toString2(fromString2(input), "base64url"), "toBase64url"); var calculateJwkThumbprint = /* @__PURE__ */ __name((args) => { const { digestAlgorithm = "sha256" } = args; const jwk = sanitizedJwk(args.jwk); let components; switch (jwk.kty) { case "EC": assertJwkClaimPresent(jwk.crv, '"crv" (Curve) Parameter'); assertJwkClaimPresent(jwk.x, '"x" (X Coordinate) Parameter'); assertJwkClaimPresent(jwk.y, '"y" (Y Coordinate) Parameter'); components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y }; break; case "OKP": assertJwkClaimPresent(jwk.crv, '"crv" (Subtype of Key Pair) Parameter'); assertJwkClaimPresent(jwk.x, '"x" (Public Key) Parameter'); components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x }; break; case "RSA": assertJwkClaimPresent(jwk.e, '"e" (Exponent) Parameter'); assertJwkClaimPresent(jwk.n, '"n" (Modulus) Parameter'); components = { e: jwk.e, kty: jwk.kty, n: jwk.n }; break; case "oct": assertJwkClaimPresent(jwk.k, '"k" (Key Value) Parameter'); components = { k: jwk.k, kty: jwk.kty }; break; default: throw new Error('"kty" (Key Type) Parameter missing or unsupported'); } const data = JSON.stringify(components); return digestAlgorithm === "sha512" ? digestMethodParams("SHA-512").digestMethod(data, "base64url") : digestMethodParams("SHA-256").digestMethod(data, "base64url"); }, "calculateJwkThumbprint"); var toJwkFromKey = /* @__PURE__ */ __name((key, opts) => { const isPrivateKey = "privateKeyHex" in key; return toJwk(key.publicKeyHex, key.type, { ...opts, key, isPrivateKey }); }, "toJwkFromKey"); var toJwk = /* @__PURE__ */ __name((publicKeyHex, type, opts) => { const { key, noKidThumbprint = false } = opts ?? {}; if (key && key.publicKeyHex !== publicKeyHex && opts?.isPrivateKey !== true) { throw Error(`Provided key with id ${key.kid}, has a different public key hex ${key.publicKeyHex} than supplied public key ${publicKeyHex}`); } let jwk; switch (type) { case "Ed25519": jwk = toEd25519OrX25519Jwk(publicKeyHex, { ...opts, crv: JoseCurve.Ed25519 }); break; case "X25519": jwk = toEd25519OrX25519Jwk(publicKeyHex, { ...opts, crv: JoseCurve.X25519 }); break; case "Secp256k1": jwk = toSecp256k1Jwk(publicKeyHex, opts); break; case "Secp256r1": jwk = toSecp256r1Jwk(publicKeyHex, opts); break; case "RSA": jwk = toRSAJwk(publicKeyHex, opts); break; default: throw new Error(`not_supported: Key type ${type} not yet supported for this did:jwk implementation`); } if (!jwk.kid && !noKidThumbprint) { jwk["kid"] = calculateJwkThumbprint({ jwk }); } return sanitizedJwk(jwk); }, "toJwk"); var jwkToRawHexKey = /* @__PURE__ */ __name(async (jwk) => { jwk = sanitizedJwk(jwk); if (jwk.kty === "RSA") { return rsaJwkToRawHexKey(jwk); } else if (jwk.kty === "EC") { return ecJwkToRawHexKey(jwk); } else if (jwk.kty === "OKP") { return okpJwkToRawHexKey(jwk); } else if (jwk.kty === "oct") { return octJwkToRawHexKey(jwk); } else { throw new Error(`Unsupported key type: ${jwk.kty}`); } }, "jwkToRawHexKey"); function rsaJwkToRawHexKey(jwk) { function encodeInteger(bytes) { if (bytes[0] & 128) { bytes = Uint8Array.from([ 0, ...bytes ]); } const len = encodeLength(bytes.length); return Uint8Array.from([ 2, ...len, ...bytes ]); } __name(encodeInteger, "encodeInteger"); function encodeLength(len) { if (len < 128) { return Uint8Array.of(len); } let hex = len.toString(16); if (hex.length % 2 === 1) { hex = "0" + hex; } const lenBytes = Uint8Array.from(hex.match(/.{2}/g).map((h) => parseInt(h, 16))); return Uint8Array.of(128 | lenBytes.length, ...lenBytes); } __name(encodeLength, "encodeLength"); function encodeSequence(elements) { const content = elements.reduce((acc, elm) => Uint8Array.from([ ...acc, ...elm ]), new Uint8Array()); const len = encodeLength(content.length); return Uint8Array.from([ 48, ...len, ...content ]); } __name(encodeSequence, "encodeSequence"); function base64UrlToBytes(b64url) { return fromString2(b64url, "base64url"); } __name(base64UrlToBytes, "base64UrlToBytes"); jwk = sanitizedJwk(jwk); if (!jwk.n || !jwk.e) { throw new Error("RSA JWK must contain 'n' and 'e' properties."); } const modulusBytes = base64UrlToBytes(jwk.n); const exponentBytes = base64UrlToBytes(jwk.e); const sequence = encodeSequence([ encodeInteger(modulusBytes), encodeInteger(exponentBytes) ]); const result = toString2(sequence, "hex"); return result; } __name(rsaJwkToRawHexKey, "rsaJwkToRawHexKey"); function ecJwkToRawHexKey(jwk) { jwk = sanitizedJwk(jwk); if (!jwk.x || !jwk.y) { throw new Error("EC JWK must contain 'x' and 'y' properties."); } const x = fromString2(jwk.x.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""), "base64url"); const y = fromString2(jwk.y.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""), "base64url"); return "04" + toString2(x, "hex") + toString2(y, "hex"); } __name(ecJwkToRawHexKey, "ecJwkToRawHexKey"); function okpJwkToRawHexKey(jwk) { jwk = sanitizedJwk(jwk); if (!jwk.x) { throw new Error("OKP JWK must contain 'x' property."); } const x = fromString2(jwk.x.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""), "base64url"); return toString2(x, "hex"); } __name(okpJwkToRawHexKey, "okpJwkToRawHexKey"); function octJwkToRawHexKey(jwk) { jwk = sanitizedJwk(jwk); if (!jwk.k) { throw new Error("Octet JWK must contain 'k' property."); } const key = fromString2(jwk.k.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""), "base64url"); return toString2(key, "hex"); } __name(octJwkToRawHexKey, "octJwkToRawHexKey"); var jwkDetermineUse = /* @__PURE__ */ __name((type, suppliedUse) => { return suppliedUse ? suppliedUse : SIG_KEY_ALGS.includes(type) ? JwkKeyUse.Signature : ENC_KEY_ALGS.includes(type) ? JwkKeyUse.Encryption : void 0; }, "jwkDetermineUse"); var assertProperKeyLength = /* @__PURE__ */ __name((keyHex, expectedKeyLength) => { if (Array.isArray(expectedKeyLength)) { if (!expectedKeyLength.includes(keyHex.length)) { throw Error(`Invalid key length. Needs to be a hex string with length from ${JSON.stringify(expectedKeyLength)} instead of ${keyHex.length}. Input: ${keyHex}`); } } else if (keyHex.length !== expectedKeyLength) { throw Error(`Invalid key length. Needs to be a hex string with length ${expectedKeyLength} instead of ${keyHex.length}. Input: ${keyHex}`); } }, "assertProperKeyLength"); var toSecp256k1Jwk = /* @__PURE__ */ __name((keyHex, opts) => { const { use } = opts ?? {}; logger.debug(`toSecp256k1Jwk keyHex: ${keyHex}, length: ${keyHex.length}`); if (opts?.isPrivateKey) { assertProperKeyLength(keyHex, [ 64 ]); } else { assertProperKeyLength(keyHex, [ 66, 130 ]); } const secp256k12 = new elliptic.ec("secp256k1"); const keyBytes = fromString2(keyHex, "base16"); const keyPair = opts?.isPrivateKey ? secp256k12.keyFromPrivate(keyBytes) : secp256k12.keyFromPublic(keyBytes); const pubPoint = keyPair.getPublic(); return sanitizedJwk({ alg: JoseSignatureAlgorithm.ES256K, ...use !== void 0 && { use }, kty: JwkKeyType.EC, crv: JoseCurve.secp256k1, x: hexToBase64(pubPoint.getX().toString("hex"), "base64url"), y: hexToBase64(pubPoint.getY().toString("hex"), "base64url"), ...opts?.isPrivateKey && { d: hexToBase64(keyPair.getPrivate("hex"), "base64url") } }); }, "toSecp256k1Jwk"); var toSecp256r1Jwk = /* @__PURE__ */ __name((keyHex, opts) => { const { use } = opts ?? {}; logger.debug(`toSecp256r1Jwk keyHex: ${keyHex}, length: ${keyHex.length}`); if (opts?.isPrivateKey) { assertProperKeyLength(keyHex, [ 64 ]); } else { assertProperKeyLength(keyHex, [ 66, 130 ]); } const secp256r1 = new elliptic.ec("p256"); const keyBytes = fromString2(keyHex, "base16"); logger.debug(`keyBytes length: ${keyBytes}`); const keyPair = opts?.isPrivateKey ? secp256r1.keyFromPrivate(keyBytes) : secp256r1.keyFromPublic(keyBytes); const pubPoint = keyPair.getPublic(); return sanitizedJwk({ alg: JoseSignatureAlgorithm.ES256, ...use !== void 0 && { use }, kty: JwkKeyType.EC, crv: JoseCurve.P_256, x: hexToBase64(pubPoint.getX().toString("hex"), "base64url"), y: hexToBase64(pubPoint.getY().toString("hex"), "base64url"), ...opts?.isPrivateKey && { d: hexToBase64(keyPair.getPrivate("hex"), "base64url") } }); }, "toSecp256r1Jwk"); var toEd25519OrX25519Jwk = /* @__PURE__ */ __name((publicKeyHex, opts) => { assertProperKeyLength(publicKeyHex, 64); const { use } = opts ?? {}; return sanitizedJwk({ alg: JoseSignatureAlgorithm.EdDSA, ...use !== void 0 && { use }, kty: JwkKeyType.OKP, crv: opts?.crv ?? JoseCurve.Ed25519, x: hexToBase64(publicKeyHex, "base64url") }); }, "toEd25519OrX25519Jwk"); var toRSAJwk = /* @__PURE__ */ __name((publicKeyHex, opts) => { function parseDerIntegers(pubKeyHex) { const bytes = Buffer.from(pubKeyHex, "hex"); let offset = 0; if (bytes[offset++] !== 48) throw new Error("Not a SEQUENCE"); let len = bytes[offset++]; if (len & 128) { const nBytes = len & 127; len = 0; for (let i = 0; i < nBytes; i++) { len = (len << 8) + bytes[offset++]; } } if (bytes[offset] !== 2) { if (bytes[offset++] !== 48) throw new Error("Expected alg-ID SEQUENCE"); let algLen = bytes[offset++]; if (algLen & 128) { const nB = algLen & 127; algLen = 0; for (let i = 0; i < nB; i++) algLen = (algLen << 8) + bytes[offset++]; } offset += algLen; if (bytes[offset++] !== 3) throw new Error("Expected BIT STRING"); let bitLen = bytes[offset++]; if (bitLen & 128) { const nB = bitLen & 127; bitLen = 0; for (let i = 0; i < nB; i++) bitLen = (bitLen << 8) + bytes[offset++]; } offset += 1; if (bytes[offset++] !== 48) throw new Error("Expected inner SEQUENCE"); let innerLen = bytes[offset++]; if (innerLen & 128) { const nB = innerLen & 127; innerLen = 0; for (let i = 0; i < nB; i++) innerLen = (innerLen << 8) + bytes[offset++]; } } if (bytes[offset++] !== 2) throw new Error("Expected INTEGER for modulus"); let modLen = bytes[offset++]; if (modLen & 128) { const nB = modLen & 127; modLen = 0; for (let i = 0; i < nB; i++) modLen = (modLen << 8) + bytes[offset++]; } let modulusBytes = bytes.slice(offset, offset + modLen); offset += modLen; if (modulusBytes[0] === 0) { modulusBytes = modulusBytes.slice(1); } if (bytes[offset++] !== 2) throw new Error("Expected INTEGER for exponent"); let expLen = bytes[offset++]; if (expLen & 128) { const nB = expLen & 127; expLen = 0; for (let i = 0; i < nB; i++) expLen = (expLen << 8) + bytes[offset++]; } const exponentBytes = bytes.slice(offset, offset + expLen); return { modulus: modulusBytes.toString("hex"), exponent: exponentBytes.toString("hex") }; } __name(parseDerIntegers, "parseDerIntegers"); const meta = opts?.key?.meta; if (meta?.publicKeyJwk || meta?.publicKeyPEM) { if (meta?.publicKeyJwk) { return meta.publicKeyJwk; } const publicKeyPEM = meta?.publicKeyPEM ?? hexToPEM(publicKeyHex, "public"); const jwk = PEMToJwk(publicKeyPEM, "public"); return jwk; } const { modulus, exponent } = parseDerIntegers(publicKeyHex); const sanitized = sanitizedJwk({ kty: "RSA", n: hexToBase64(modulus, "base64url"), e: hexToBase64(exponent, "base64url") }); return sanitized; }, "toRSAJwk"); var padLeft = /* @__PURE__ */ __name((args) => { const { data } = args; const size = args.size ?? 32; const padString = args.padString ?? "0"; if (data.length >= size) { return data; } if (padString && padString.length === 0) { throw Error(`Pad string needs to have at least a length of 1`); } const length = padString.length; return padString.repeat((size - data.length) / length) + data; }, "padLeft"); var OID = { [0]: new Uint8Array([ 6, 7, 42, 134, 72, 206, 61, 2, 1 ]), [1]: new Uint8Array([ 6, 8, 42, 134, 72, 206, 61, 3, 1, 7 ]), [2]: new Uint8Array([ 6, 3, 43, 101, 112 ]) }; var compareUint8Arrays = /* @__PURE__ */ __name((a, b) => { if (a.length !== b.length) { return false; } for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) { return false; } } return true; }, "compareUint8Arrays"); var findSubarray = /* @__PURE__ */ __name((haystack, needle) => { for (let i = 0; i <= haystack.length - needle.length; i++) { if (compareUint8Arrays(haystack.subarray(i, i + needle.length), needle)) { return i; } } return -1; }, "findSubarray"); var getTargetOID = /* @__PURE__ */ __name((keyType) => { switch (keyType) { case "Secp256k1": return OID[0]; case "Secp256r1": return OID[1]; case "Ed25519": return OID[2]; default: throw new Error(`Unsupported key type: ${keyType}`); } }, "getTargetOID"); var isAsn1Der = /* @__PURE__ */ __name((key) => key[0] === 48, "isAsn1Der"); var asn1DerToRawPublicKey = /* @__PURE__ */ __name((derKey, keyType) => { if (!isAsn1Der(derKey)) { throw new Error("Invalid DER encoding: Expected to start with sequence tag"); } let index = 2; if (derKey[1] & 128) { const lengthBytesCount = derKey[1] & 127; index += lengthBytesCount; } const targetOid = getTargetOID(keyType); const oidIndex = findSubarray(derKey, targetOid); if (oidIndex === -1) { throw new Error(`OID for ${keyType} not found in DER encoding`); } index = oidIndex + targetOid.length; while (index < derKey.length && derKey[index] !== 3) { index++; } if (index >= derKey.length) { throw new Error("Invalid DER encoding: Bit string not found"); } index += 2; index++; return derKey.slice(index); }, "asn1DerToRawPublicKey"); var isRawCompressedPublicKey = /* @__PURE__ */ __name((key) => key.length === 33 && (key[0] === 2 || key[0] === 3), "isRawCompressedPublicKey"); var toRawCompressedHexPublicKey = /* @__PURE__ */ __name((rawPublicKey, keyType) => { if (isRawCompressedPublicKey(rawPublicKey)) { return hexStringFromUint8Array(rawPublicKey); } if (keyType === "Secp256k1" || keyType === "Secp256r1") { if (rawPublicKey[0] === 4 && rawPublicKey.length === 65) { const xCoordinate = rawPublicKey.slice(1, 33); const yCoordinate = rawPublicKey.slice(33); const prefix = new Uint8Array([ yCoordinate[31] % 2 === 0 ? 2 : 3 ]); const resultKey = hexStringFromUint8Array(new Uint8Array([ ...prefix, ...xCoordinate ])); logger.debug(`converted public key ${hexStringFromUint8Array(rawPublicKey)} to ${resultKey}`); return resultKey; } return toString2(rawPublicKey, "base16"); } else if (keyType === "Ed25519") { return toString2(rawPublicKey, "base16"); } throw new Error(`Unsupported key type: ${keyType}`); }, "toRawCompressedHexPublicKey"); var hexStringFromUint8Array = /* @__PURE__ */ __name((value) => toString2(value, "base16"), "hexStringFromUint8Array"); var signatureAlgorithmFromKey = /* @__PURE__ */ __name(async (args) => { const { key } = args; return signatureAlgorithmFromKeyType({ type: key.type }); }, "signatureAlgorithmFromKey"); var signatureAlgorithmFromKeyType = /* @__PURE__ */ __name((args) => { const { type } = args; switch (type) { case "Ed25519": case "X25519": return JoseSignatureAlgorithm.EdDSA; case "Secp256r1": return JoseSignatureAlgorithm.ES256; case "Secp384r1": return JoseSignatureAlgorithm.ES384; case "Secp521r1": return JoseSignatureAlgorithm.ES512; case "Secp256k1": return JoseSignatureAlgorithm.ES256K; case "RSA": return JoseSignatureAlgorithm.PS256; default: throw new Error(`Key type '${type}' not supported`); } }, "signatureAlgorithmFromKeyType"); var keyTypeFromCryptographicSuite = /* @__PURE__ */ __name((args) => { const { crv, kty, alg } = args; switch (alg) { case "RSASSA-PSS": case "RS256": case "RS384": case "RS512": case "PS256": case "PS384": case "PS512": return "RSA"; } switch (crv) { case "EdDSA": case "Ed25519": case "Ed25519Signature2018": case "Ed25519Signature2020": case "JcsEd25519Signature2020": return "Ed25519"; case "JsonWebSignature2020": case "ES256": case "ECDSA": case "P-256": return "Secp256r1"; case "ES384": case "P-384": return "Secp384r1"; case "ES512": case "P-521": return "Secp521r1"; case "EcdsaSecp256k1Signature2019": case "secp256k1": case "ES256K": case "EcdsaSecp256k1VerificationKey2019": case "EcdsaSecp256k1RecoveryMethod2020": return "Secp256k1"; } if (kty) { return kty; } throw new Error(`Cryptographic suite '${crv}' not supported`); }, "keyTypeFromCryptographicSuite"); function removeNulls(obj) { Object.keys(obj).forEach((key) => { if (obj[key] && typeof obj[key] === "object") removeNulls(obj[key]); else if (obj[key] == null) delete obj[key]; }); return obj; } __name(removeNulls, "removeNulls"); var globalCrypto = /* @__PURE__ */ __name((setGlobal, suppliedCrypto) => { let webcrypto; if (typeof suppliedCrypto !== "undefined") { webcrypto = suppliedCrypto; } else if (typeof crypto !== "undefined") { webcrypto = crypto; } else if (typeof global.crypto !== "undefined") { webcrypto = global.crypto; } else { if (typeof global.window?.crypto?.subtle !== "undefined") { webcrypto = global.window.crypto; } else { webcrypto = import("crypto"); } } if (setGlobal) { global.crypto = webcrypto; } return webcrypto; }, "globalCrypto"); var sanitizedJwk = /* @__PURE__ */ __name((input) => { const inputJwk = typeof input["toJsonDTO"] === "function" ? input["toJsonDTO"]() : { ...input }; const jwk = { ...inputJwk, ...inputJwk.x && { x: base64ToBase64Url(inputJwk.x) }, ...inputJwk.y && { y: base64ToBase64Url(inputJwk.y) }, ...inputJwk.d && { d: base64ToBase64Url(inputJwk.d) }, ...inputJwk.n && { n: base64ToBase64Url(inputJwk.n) }, ...inputJwk.e && { e: base64ToBase64Url(inputJwk.e) }, ...inputJwk.k && { k: base64ToBase64Url(inputJwk.k) } }; return removeNulls(jwk); }, "sanitizedJwk"); var base64ToBase64Url = /* @__PURE__ */ __name((input) => { return input.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); }, "base64ToBase64Url"); async function verifyRawSignature({ data, signature, key: inputKey, opts }) { function jwkPropertyToBigInt(jwkProp) { const byteArray = fromString2(jwkProp, "base64url"); const hex = toString2(byteArray, "hex"); return BigInt(`0x${hex}`); } __name(jwkPropertyToBigInt, "jwkPropertyToBigInt"); try { debug(`verifyRawSignature for: ${inputKey}`); const jwk = sanitizedJwk(inputKey); validateJwk(jwk, { crvOptional: true }); const keyType = keyTypeFromCryptographicSuite({ crv: jwk.crv, kty: jwk.kty, alg: jwk.alg }); const publicKeyHex = await jwkToRawHexKey(jwk); switch (keyType) { case "Secp256k1": return secp256k1.verify(signature, data, publicKeyHex, { format: "compact", prehash: true }); case "Secp256r1": return p256.verify(signature, data, publicKeyHex, { format: "compact", prehash: true }); case "Secp384r1": return p384.verify(signature, data, publicKeyHex, { format: "compact", prehash: true }); case "Secp521r1": return p521.verify(signature, data, publicKeyHex, { format: "compact", prehash: true }); case "Ed25519": return ed25519.verify(signature, data, fromString2(publicKeyHex, "hex")); case "Bls12381G1": case "Bls12381G2": return bls12_381.verify(signature, data, fromString2(publicKeyHex, "hex")); case "RSA": { const signatureAlgorithm = opts?.signatureAlg ?? jwk.alg ?? JoseSignatureAlgorithm.PS256; const hashAlg = signatureAlgorithm === (JoseSignatureAlgorithm.RS512 || JoseSignatureAlgorithm.PS512) ? sha5122 : signatureAlgorithm === (JoseSignatureAlgorithm.RS384 || JoseSignatureAlgorithm.PS384) ? sha3842 : sha2562; switch (signatureAlgorithm) { case JoseSignatureAlgorithm.RS256: return rsa.PKCS1_SHA256.verify({ n: jwkPropertyToBigInt(jwk.n), e: jwkPropertyToBigInt(jwk.e) }, data, signature); case JoseSignatureAlgorithm.RS384: return rsa.PKCS1_SHA384.verify({ n: jwkPropertyToBigInt(jwk.n), e: jwkPropertyToBigInt(jwk.e) }, data, signature); case JoseSignatureAlgorithm.RS512: return rsa.PKCS1_SHA512.verify({ n: jwkPropertyToBigInt(jwk.n), e: jwkPropertyToBigInt(jwk.e) }, data, signature); case JoseSignatureAlgorithm.PS256: case JoseSignatureAlgorithm.PS384: case JoseSignatureAlgorithm.PS512: if (typeof crypto !== "undefined" && typeof crypto.subtle !== "undefined") { const key = await cryptoSubtleImportRSAKey(jwk, "RSA-PSS"); const saltLength = signatureAlgorithm === JoseSignatureAlgorithm.PS256 ? 32 : signatureAlgorithm === JoseSignatureAlgorithm.PS384 ? 48 : 64; return crypto.subtle.verify({ name: "rsa-pss", hash: hashAlg, saltLength }, key, signature, data); } console.warn(`Using fallback for RSA-PSS verify signature, which is known to be flaky!!`); return rsa.PSS(hashAlg, rsa.mgf1(hashAlg)).verify({ n: jwkPropertyToBigInt(jwk.n), e: jwkPropertyToBigInt(jwk.e) }, data, signature); } } } throw Error(`Unsupported key type for signature validation: ${keyType}`); } catch (error) { logger.error(`Error: ${error}`); throw error; } } __name(verifyRawSignature, "verifyRawSignature"); function readLength(bytes, offset) { const first = bytes[offset]; if (first < 128) { return { length: first, lengthBytes: 1 }; } const numBytes = first & 127; let length = 0; for (let i = 0; i < numBytes; i++) { length = length << 8 | bytes[offset + 1 + i]; } return { length, lengthBytes: 1 + numBytes }; } __name(readLength, "readLength"); function toPkcs1(derBytes) { if (derBytes[0] !== 48) { throw new Error("Invalid DER: expected SEQUENCE"); } const { lengthBytes: outerLenBytes } = readLength(derBytes, 1); const outerHeaderLen = 1 + outerLenBytes; const innerTag = derBytes[outerHeaderLen]; if (innerTag === 2) { return derBytes; } if (innerTag !== 48) { throw new Error("Unexpected DER tag, not PKCS#1 or SPKI"); } const { length: algLen, lengthBytes: algLenBytes } = readLength(derBytes, outerHeaderLen + 1); const algHeaderLen = 1 + algLenBytes; const algIdEnd = outerHeaderLen + algHeaderLen + algLen; if (derBytes[algIdEnd] !== 3) { throw new Error("Expected BIT STRING after algId"); } const { length: bitStrLen, lengthBytes: bitStrLenBytes } = readLength(derBytes, algIdEnd + 1); const bitStrHeaderLen = 1 + bitStrLenBytes; const bitStrStart = algIdEnd + bitStrHeaderLen; const unusedBits = derBytes[bitStrStart]; if (unusedBits !== 0) { throw new Error(`Unexpected unused bits: ${unusedBits}`); } const pkcs1Start = bitStrStart + 1; const pkcs1Len = bitStrLen - 1; return derBytes.slice(pkcs1Start, pkcs1Start + pkcs1Len); } __name(toPkcs1, "toPkcs1"); function toPkcs1FromHex(publicKeyHex) { const pkcs1 = toPkcs1(fromString2(publicKeyHex, "hex")); return toString2(pkcs1, "hex"); } __name(toPkcs1FromHex, "toPkcs1FromHex"); // src/conversion.ts import { ICoseCurve, ICoseKeyOperation, ICoseKeyType, ICoseSignatureAlgorithm, JoseCurve as JoseCurve2, JoseKeyOperation, JoseSignatureAlgorithm as JoseSignatureAlgorithm2, JwkKeyType as JwkKeyType2 } from "@sphereon/ssi-types"; function coseKeyToJwk(coseKey) { const { x5chain, key_ops, crv, alg, baseIV, kty, ...rest } = coseKey; return removeNulls({ ...rest, kty: coseToJoseKty(kty), ...crv && { crv: coseToJoseCurve(crv) }, ...key_ops && { key_ops: key_ops.map(coseToJoseKeyOperation) }, ...alg && { alg: coseToJoseSignatureAlg(alg) }, ...baseIV && { iv: baseIV }, ...x5chain && { x5c: x5chain } }); } __name(coseKeyToJwk, "coseKeyToJwk"); function jwkToCoseKey(jwk) { const { x5c, key_ops, crv, alg, iv, kty, ...rest } = jwk; return removeNulls({ ...rest, kty: joseToCoseKty(kty), ...crv && { crv: joseToCoseCurve(crv) }, ...key_ops && { key_ops: key_ops.map(joseToCoseKeyOperation) }, ...alg && { alg: joseToCoseSignatureAlg(alg) }, ...iv && { baseIV: iv }, ...x5c && { x5chain: x5c } }); } __name(jwkToCoseKey, "jwkToCoseKey"); function coseToJoseKty(kty) { switch (kty) { case ICoseKeyType.EC2: return JwkKeyType2.EC; case ICoseKeyType.RSA: return JwkKeyType2.RSA; case ICoseKeyType.Symmetric: return JwkKeyType2.oct; case ICoseKeyType.OKP: return JwkKeyType2.OKP; default: throw Error(`Key type ${kty} not supported in JWA`); } } __name(coseToJoseKty, "coseToJoseKty"); function joseToCoseKty(kty) { switch (kty) { case "EC": return ICoseKeyType.EC2; case "RSA": return ICoseKeyType.RSA; case "oct": return ICoseKeyType.Symmetric; case "OKP": return ICoseKeyType.OKP; default: throw Error(`Key type ${kty} not supported in Cose`); } } __name(joseToCoseKty, "joseToCoseKty"); function coseToJoseSignatureAlg(coseAlg) { switch (coseAlg) { case ICoseSignatureAlgorithm.ES256K: return JoseSignatureAlgorithm2.ES256K; case ICoseSignatureAlgorithm.ES256: return JoseSignatureAlgorithm2.ES256; case ICoseSignatureAlgorithm.ES384: return JoseSignatureAlgorithm2.ES384; case ICoseSignatureAlgorithm.ES512: return JoseSignatureAlgorithm2.ES512; case ICoseSignatureAlgorithm.PS256: return JoseSignatureAlgorithm2.PS256; case ICoseSignatureAlgorithm.PS384: return JoseSignatureAlgorithm2.PS384; case ICoseSignatureAlgorithm.PS512: return JoseSignatureAlgorithm2.PS512; case ICoseSignatureAlgorithm.HS256: return JoseSignatureAlgorithm2.HS256; case ICoseSignatureAlgorithm.HS384: return JoseSignatureAlgorithm2.HS384; case ICoseSignatureAlgorithm.HS512: return JoseSignatureAlgorithm2.HS512; case ICoseSignatureAlgorithm.EdDSA: return JoseSignatureAlgorithm2.EdDSA; default: throw Error(`Signature algorithm ${coseAlg} not supported in Jose`); } } __name(coseToJoseSignatureAlg, "coseToJoseSignatureAlg"); function joseToCoseSignatureAlg(joseAlg) { switch (joseAlg) { case (JoseSignatureAlgorithm2.ES256K, "ES256K"): return ICoseSignatureAlgorithm.ES256K; case (JoseSignatureAlgorithm2.ES256, "ES256"): return ICoseSignatureAlgorithm.ES256; case (JoseSignatureAlgorithm2.ES384, "ES384"): return ICoseSignatureAlgorithm.ES384; case (JoseSignatureAlgorithm2.ES512, "ES512"): return ICoseSignatureAlgorithm.ES512; case (JoseSignatureAlgorithm2.PS256, "PS256"): return ICoseSignatureAlgorithm.PS256; case (JoseSignatureAlgorithm2.PS384, "PS384"): return ICoseSignatureAlgorithm.PS384; case (JoseSignatureAlgorithm2.PS512, "PS512"): return ICoseSignatureAlgorithm.PS512; case (JoseSignatureAlgorithm2.HS256, "HS256"): return ICoseSignatureAlgorithm.HS256; case (JoseSignatureAlgorithm2.HS384, "HS384"): return ICoseSignatureAlgorithm.HS384; case (JoseSignatureAlgorithm2.HS512, "HS512"): return ICoseSignatureAlgorithm.HS512; case (JoseSignatureAlgorithm2.EdDSA, "EdDSA"): return ICoseSignatureAlgorithm.EdDSA; default: throw Error(`Signature algorithm ${joseAlg} not supported in Cose`); } } __name(joseToCoseSignatureAlg, "joseToCoseSignatureAlg"); function joseToCoseKeyOperation(keyOp) { switch (keyOp) { case (JoseKeyOperation.SIGN, "sign"): return ICoseKeyOperation.SIGN; case (JoseKeyOperation.VERIFY, "verify"): return ICoseKeyOperation.VERIFY; case (JoseKeyOperation.ENCRYPT, "encrypt"): return ICoseKeyOperation.ENCRYPT; case (JoseKeyOperation.DECRYPT, "decrypt"): return ICoseKeyOperation.DECRYPT; case (JoseKeyOperation.WRAP_KEY, "wrapKey"): return ICoseKeyOperation.WRAP_KEY; case (JoseKeyOperation.UNWRAP_KEY, "unwrapKey"): return ICoseKeyOperation.UNWRAP_KEY; case (JoseKeyOperation.DERIVE_KEY, "deriveKey"): return ICoseKeyOperation.DERIVE_KEY; case (JoseKeyOperation.DERIVE_BITS, "deriveBits"): return ICoseKeyOperation.DERIVE_BITS; default: throw Error(`Key operation ${keyOp} not supported in Cose`); } } __name(joseToCoseKeyOperation, "joseToCoseKeyOperation"); function coseToJoseKeyOperation(keyOp) { switch (keyOp) { case ICoseKeyOperation.SIGN: return JoseKeyOperation.SIGN; case ICoseKeyOperation.VERIFY: return JoseKeyOperation.VERIFY; case ICoseKeyOperation.ENCRYPT: return JoseKeyOperation.ENCRYPT; case ICoseKeyOperation.DECRYPT: return JoseKeyOperation.DECRYPT; case ICoseKeyOperation.WRAP_KEY: return JoseKeyOperation.WRAP_KEY; case ICoseKeyOperation.UNWRAP_KEY: return JoseKeyOperation.UNWRAP_KEY; case ICoseKeyOperation.DERIVE_KEY: return JoseKeyOperation.DERIVE_KEY; case ICoseKeyOperation.DERIVE_BITS: return JoseKeyOperation.DERIVE_BITS; default: throw Error(`Key operation ${keyOp} not supported in Jose`); } } __name(coseToJoseKeyOperation, "coseToJoseKeyOperation"); function joseToCoseCurve(curve) { switch (curve) { case (JoseCurve2.P_256, "P-256"): return ICoseCurve.P_256; case (JoseCurve2.P_384, "P-384"): return ICoseCurve.P_384; case (JoseCurve2.P_521, "P-521"): return ICoseCurve.P_521; case (JoseCurve2.X25519, "X25519"): return ICoseCurve.X25519; case (JoseCurve2.X448, "X448"): return ICoseCurve.X448; case (JoseCurve2.Ed25519, "Ed25519"): return ICoseCurve.Ed25519; case (JoseCurve2.Ed448, "Ed448"): return ICoseCurve.Ed448; case (JoseCurve2.secp256k1, "secp256k1"): return ICoseCurve.secp256k1; default: throw Error(`Curve ${curve} not supported in Cose`); } } __name(joseToCoseCurve, "joseToCoseCurve"); function coseToJoseCurve(curve) { switch (curve) { case ICoseCurve.P_256: return JoseCurve2.P_256; case ICoseCurve.P_384: return JoseCurve2.P_384; case ICoseCurve.P_521: return JoseCurve2.P_521; case ICoseCurve.X25519: return JoseCurve2.X25519; case ICoseCurve.X448: return JoseCurve2.X448; case ICoseCurve.Ed25519: return JoseCurve2.Ed25519; case ICoseCurve.Ed448: return JoseCurve2.Ed448; case ICoseCurve.secp256k1: return JoseCurve2.secp256k1; default: throw Error(`Curve ${curve} not supported in Jose`); } } __name(coseToJoseCurve, "coseToJoseCurve"); export { ENC_KEY_ALGS, JWK_JCS_PUB_NAME, JWK_JCS_PUB_PREFIX, JwkKeyUse, Key, SIG_KEY_ALGS, asn1DerToRawPublicKey, calculateJwkThumbprint, calculateJwkThumbprintForKey, coseKeyToJwk, coseToJoseCurve, coseToJoseKeyOperation, coseToJoseKty, coseToJoseSignatureAlg, digestMethodParams, generatePrivateKeyHex, getKms, globalCrypto, hexStringFromUint8Array, importProvidedOrGeneratedKey, isAsn1Der, isRawCompressedPublicKey, jcsCanonicalize, joseToCoseCurve, joseToCoseKeyOperation, joseToCoseKty, joseToCoseSignatureAlg, jwkDetermineUse, jwkJcsDecode, jwkJcsEncode, jwkToCoseKey, jwkToRawHexKey, keyTypeFromCryptographicSuite, logger, minimalJwk, padLeft, removeNulls, rsaJwkToRawHexKey, sanitizedJwk, shaHasher, signatureAlgorithmFromKey, signatureAlgorithmFromKeyType, toBase64url, toJwk, toJwkFromKey, toPkcs1, toPkcs1FromHex, toRawCompressedHexPublicKey, validateJwk, verifyRawSignature }; //# sourceMappingURL=index.js.map