unjwt 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/THIRD-PARTY-LICENSES.md +63 -0
- package/dist/_chunks/_internal.mjs +88 -0
- package/dist/_chunks/index.d.mts +401 -41
- package/dist/_chunks/jwe.d.mts +82 -0
- package/dist/_chunks/jwe.mjs +407 -0
- package/dist/_chunks/{_crypto.mjs → jwk.mjs} +637 -26
- package/dist/_chunks/jws.d.mts +111 -0
- package/dist/_chunks/jws.mjs +264 -2031
- package/dist/_chunks/libs/rou3.mjs +5 -0
- package/dist/_chunks/libs/unsecure.d.mts +94 -0
- package/dist/_chunks/libs/unsecure.mjs +144 -0
- package/dist/_chunks/utils.mjs +222 -211
- package/dist/adapters/h3v1/index.d.mts +9 -9
- package/dist/adapters/h3v1/index.mjs +13 -75
- package/dist/adapters/h3v2/index.d.mts +9 -9
- package/dist/adapters/h3v2/index.mjs +14 -38
- package/dist/core/jwe.d.mts +3 -40
- package/dist/core/jwe.mjs +3 -161
- package/dist/core/jwk.d.mts +202 -46
- package/dist/core/jwk.mjs +3 -686
- package/dist/core/jws.d.mts +3 -31
- package/dist/core/jws.mjs +3 -104
- package/dist/core/utils/index.d.mts +74 -60
- package/dist/core/utils/index.mjs +3 -2
- package/dist/index.d.mts +6 -7
- package/dist/index.mjs +5 -5
- package/package.json +24 -22
- package/dist/_chunks/error.d.mts +0 -67
- package/dist/_chunks/jwk.d.mts +0 -708
- package/dist/core/_crypto/index.d.mts +0 -71
- package/dist/core/_crypto/index.mjs +0 -2
package/dist/core/jwe.mjs
CHANGED
|
@@ -1,161 +1,3 @@
|
|
|
1
|
-
import { D as
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
//#region src/core/jwe.ts
|
|
5
|
-
async function encrypt(payload, key, options = {}) {
|
|
6
|
-
const { protectedHeader: userHeader, cek: providedCek, contentEncryptionIV: providedContentIV, keyManagementIV, p2s, p2c, ecdh } = options;
|
|
7
|
-
let { alg, enc } = options;
|
|
8
|
-
if (!alg) {
|
|
9
|
-
if (typeof key === "string" || key instanceof Uint8Array) alg = "PBES2-HS256+A128KW";
|
|
10
|
-
else if (isJWK(key)) alg = key.alg === "A128GCM" || key.alg === "A192GCM" || key.alg === "A256GCM" ? `${key.alg}KW` : key.alg;
|
|
11
|
-
}
|
|
12
|
-
if (!alg) throw new TypeError("JWE \"alg\" (Key Management Algorithm) must be provided in options or inferable from the key");
|
|
13
|
-
if (!enc) if (alg === "dir") {
|
|
14
|
-
enc = isJWK(key) && "enc" in key ? key.enc : void 0;
|
|
15
|
-
if (!enc) throw new TypeError("JWE \"enc\" must be provided when alg is \"dir\"");
|
|
16
|
-
} else enc = isJWK(key) && "enc" in key ? key.enc : "A128GCM";
|
|
17
|
-
const jweKeyManagementParams = {};
|
|
18
|
-
if (keyManagementIV) jweKeyManagementParams.iv = keyManagementIV;
|
|
19
|
-
if (p2s) jweKeyManagementParams.p2s = p2s;
|
|
20
|
-
else if (alg?.startsWith("PBES2")) jweKeyManagementParams.p2s = randomBytes(16);
|
|
21
|
-
if (p2c) jweKeyManagementParams.p2c = p2c;
|
|
22
|
-
else if (alg?.startsWith("PBES2")) jweKeyManagementParams.p2c = 6e5;
|
|
23
|
-
if (ecdh?.partyUInfo) jweKeyManagementParams.apu = ecdh.partyUInfo;
|
|
24
|
-
if (ecdh?.partyVInfo) jweKeyManagementParams.apv = ecdh.partyVInfo;
|
|
25
|
-
if (ecdh?.ephemeralKey) {
|
|
26
|
-
const { epk, epkPrivateKey } = parseEphemeralKey(ecdh.ephemeralKey);
|
|
27
|
-
jweKeyManagementParams.epk = epk;
|
|
28
|
-
jweKeyManagementParams.epkPrivateKey = epkPrivateKey;
|
|
29
|
-
}
|
|
30
|
-
const wrappingKeyMaterial = await importKey(key, alg);
|
|
31
|
-
const { cek: finalCek, encryptedKey: jweEncryptedKey, parameters: keyManagementHeaderParams } = await encryptKey(alg, enc, wrappingKeyMaterial, providedCek, jweKeyManagementParams);
|
|
32
|
-
const protectedHeader = _buildJWEHeader(alg, enc, key, userHeader, keyManagementHeaderParams, payload);
|
|
33
|
-
const plaintextBytes = getPlaintextBytes(computeJwtTimeClaims(payload, protectedHeader.typ, options.expiresIn, options.currentDate) || payload);
|
|
34
|
-
const protectedHeaderEncoded = base64UrlEncode(JSON.stringify(protectedHeader));
|
|
35
|
-
const aadBytes = textEncoder.encode(protectedHeaderEncoded);
|
|
36
|
-
const contentIVBytes = providedContentIV ?? generateIV(enc);
|
|
37
|
-
const { ciphertext: contentCiphertext, tag: contentAuthTag, iv: actualContentIV } = await encrypt$1(enc, plaintextBytes, finalCek, contentIVBytes, aadBytes);
|
|
38
|
-
if (!actualContentIV) throw new JWTError("Content encryption IV was not generated or returned.", "ERR_JWE_INVALID");
|
|
39
|
-
if (!contentAuthTag) throw new JWTError("Content encryption auth tag was not generated or returned.", "ERR_JWE_INVALID");
|
|
40
|
-
return [
|
|
41
|
-
protectedHeaderEncoded,
|
|
42
|
-
jweEncryptedKey ? base64UrlEncode(jweEncryptedKey) : "",
|
|
43
|
-
base64UrlEncode(actualContentIV),
|
|
44
|
-
base64UrlEncode(contentCiphertext),
|
|
45
|
-
base64UrlEncode(contentAuthTag)
|
|
46
|
-
].join(".");
|
|
47
|
-
}
|
|
48
|
-
async function decrypt(jwe, key, options = {}) {
|
|
49
|
-
const parts = jwe.split(".");
|
|
50
|
-
if (parts.length !== 5) throw new JWTError("Invalid JWE: Must contain five sections (RFC7516, section-3).", "ERR_JWE_INVALID");
|
|
51
|
-
const [protectedHeaderEncoded, encryptedKeyEncoded, ivEncoded, ciphertextEncoded, authTagEncoded] = parts;
|
|
52
|
-
let protectedHeader;
|
|
53
|
-
try {
|
|
54
|
-
const protectedHeaderJson = base64UrlDecode(protectedHeaderEncoded);
|
|
55
|
-
protectedHeader = sanitizeObject(JSON.parse(protectedHeaderJson));
|
|
56
|
-
} catch {
|
|
57
|
-
throw new JWTError("Invalid JWE: Protected header could not be decoded.", "ERR_JWE_INVALID");
|
|
58
|
-
}
|
|
59
|
-
if (!protectedHeader || typeof protectedHeader !== "object" || !protectedHeader.alg || !protectedHeader.enc) throw new JWTError("Invalid JWE: Protected header must be an object with \"alg\" and \"enc\" properties.", "ERR_JWE_INVALID");
|
|
60
|
-
const alg = protectedHeader.alg;
|
|
61
|
-
const enc = protectedHeader.enc;
|
|
62
|
-
if (options?.algorithms && !options.algorithms.includes(alg)) throw new JWTError(`Key management algorithm not allowed: ${alg}`, "ERR_JWE_ALG_NOT_ALLOWED");
|
|
63
|
-
if (options?.encryptionAlgorithms && !options.encryptionAlgorithms.includes(enc)) throw new JWTError(`Content encryption algorithm not allowed: ${enc}`, "ERR_JWE_ALG_NOT_ALLOWED");
|
|
64
|
-
const rawKeyMaterial = typeof key === "function" ? await key(protectedHeader, jwe) : key;
|
|
65
|
-
const encryptedKeyBytes = base64UrlDecode(encryptedKeyEncoded, false);
|
|
66
|
-
const contentIVBytes = base64UrlDecode(ivEncoded, false);
|
|
67
|
-
const contentAuthTagBytes = base64UrlDecode(authTagEncoded, false);
|
|
68
|
-
const ciphertextBytes = base64UrlDecode(ciphertextEncoded, false);
|
|
69
|
-
const unwrapKeyOpts = {
|
|
70
|
-
enc,
|
|
71
|
-
format: enc.includes("GCM") ? "cryptokey" : "raw",
|
|
72
|
-
keyUsage: options?.keyUsage || ["decrypt"]
|
|
73
|
-
};
|
|
74
|
-
if (protectedHeader.iv) unwrapKeyOpts.iv = protectedHeader.iv;
|
|
75
|
-
if (protectedHeader.tag) unwrapKeyOpts.tag = protectedHeader.tag;
|
|
76
|
-
if (protectedHeader.p2s) unwrapKeyOpts.p2s = protectedHeader.p2s;
|
|
77
|
-
if (protectedHeader.p2c) unwrapKeyOpts.p2c = protectedHeader.p2c;
|
|
78
|
-
if (protectedHeader.epk) unwrapKeyOpts.epk = protectedHeader.epk;
|
|
79
|
-
if (protectedHeader.apu) unwrapKeyOpts.apu = protectedHeader.apu;
|
|
80
|
-
if (protectedHeader.apv) unwrapKeyOpts.apv = protectedHeader.apv;
|
|
81
|
-
if (options?.unwrappedKeyAlgorithm) unwrapKeyOpts.unwrappedKeyAlgorithm = options.unwrappedKeyAlgorithm;
|
|
82
|
-
if (options?.extractable) unwrapKeyOpts.extractable = options.extractable;
|
|
83
|
-
const aadBytes = textEncoder.encode(protectedHeaderEncoded);
|
|
84
|
-
let cek;
|
|
85
|
-
let plaintextBytes;
|
|
86
|
-
if (isJWKSet(rawKeyMaterial)) {
|
|
87
|
-
const candidates = getJWKsFromSet(rawKeyMaterial, _buildJWESetFilter(protectedHeader));
|
|
88
|
-
if (candidates.length === 0) throw new JWTError(`No key found in JWK Set${protectedHeader.kid ? ` with kid "${protectedHeader.kid}"` : ""}.`, "ERR_JWK_KEY_NOT_FOUND");
|
|
89
|
-
let decrypted = false;
|
|
90
|
-
for (const candidate of candidates) try {
|
|
91
|
-
const candidateCek = await unwrapKey(alg, encryptedKeyBytes, await importKey(candidate, alg), unwrapKeyOpts);
|
|
92
|
-
plaintextBytes = await decrypt$1(enc, candidateCek, ciphertextBytes, contentIVBytes, contentAuthTagBytes, aadBytes);
|
|
93
|
-
cek = candidateCek;
|
|
94
|
-
decrypted = true;
|
|
95
|
-
break;
|
|
96
|
-
} catch {}
|
|
97
|
-
if (!decrypted) throw new JWTError("JWE decryption failed.", "ERR_JWE_DECRYPTION_FAILED");
|
|
98
|
-
} else {
|
|
99
|
-
const unwrappingKey = await importKey(rawKeyMaterial, alg);
|
|
100
|
-
try {
|
|
101
|
-
cek = await unwrapKey(alg, encryptedKeyBytes, unwrappingKey, unwrapKeyOpts);
|
|
102
|
-
plaintextBytes = await decrypt$1(enc, cek, ciphertextBytes, contentIVBytes, contentAuthTagBytes, aadBytes);
|
|
103
|
-
} catch (error_) {
|
|
104
|
-
if (error_ instanceof JWTError) throw error_;
|
|
105
|
-
throw new JWTError("JWE decryption failed.", "ERR_JWE_DECRYPTION_FAILED", error_);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
const payload = decodePayloadFromBytes(plaintextBytes, protectedHeader, options?.forceUint8Array);
|
|
109
|
-
if (protectedHeader.crit || options?.recognizedHeaders?.length) validateCriticalHeadersJWE(protectedHeader, options?.recognizedHeaders);
|
|
110
|
-
if (payload && typeof payload === "object" && options.validateClaims !== false && (options.validateClaims === true || protectedHeader.typ?.toLowerCase().includes("jwt")) && !options.forceUint8Array && !(payload instanceof Uint8Array)) validateJwtClaims(payload, options);
|
|
111
|
-
const result = {
|
|
112
|
-
payload,
|
|
113
|
-
protectedHeader
|
|
114
|
-
};
|
|
115
|
-
if (options.returnCek) {
|
|
116
|
-
result.cek = isCryptoKey(cek) ? new Uint8Array(await crypto.subtle.exportKey("raw", cek)) : cek;
|
|
117
|
-
result.aad = aadBytes;
|
|
118
|
-
}
|
|
119
|
-
return result;
|
|
120
|
-
}
|
|
121
|
-
function parseEphemeralKey(ephemeralKey) {
|
|
122
|
-
let epk;
|
|
123
|
-
let epkPrivateKey;
|
|
124
|
-
if (isCryptoKeyPair(ephemeralKey)) {
|
|
125
|
-
epk = ephemeralKey.publicKey;
|
|
126
|
-
epkPrivateKey = ephemeralKey.privateKey;
|
|
127
|
-
} else if (typeof ephemeralKey === "object" && ephemeralKey !== null && "publicKey" in ephemeralKey && "privateKey" in ephemeralKey) {
|
|
128
|
-
const candidate = ephemeralKey;
|
|
129
|
-
if (!candidate.publicKey || !candidate.privateKey) throw new TypeError("ECDH-ES custom ephemeral key must include both publicKey and privateKey.");
|
|
130
|
-
epk = candidate.publicKey;
|
|
131
|
-
epkPrivateKey = candidate.privateKey;
|
|
132
|
-
} else if (isCryptoKey(ephemeralKey)) {
|
|
133
|
-
if (ephemeralKey.type !== "private") throw new TypeError("ECDH-ES custom ephemeral CryptoKey must include private key material.");
|
|
134
|
-
epk = ephemeralKey;
|
|
135
|
-
epkPrivateKey = ephemeralKey;
|
|
136
|
-
} else if (isJWK(ephemeralKey)) {
|
|
137
|
-
if (!("d" in ephemeralKey) || typeof ephemeralKey.d !== "string") throw new TypeError("ECDH-ES custom ephemeral JWK must include private parameter \"d\".");
|
|
138
|
-
epk = ephemeralKey;
|
|
139
|
-
epkPrivateKey = ephemeralKey;
|
|
140
|
-
} else throw new TypeError("Unsupported ECDH-ES ephemeral key material provided in options.");
|
|
141
|
-
return {
|
|
142
|
-
epk,
|
|
143
|
-
epkPrivateKey
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
function _buildJWESetFilter(header) {
|
|
147
|
-
const { kid, alg } = header;
|
|
148
|
-
return (k) => (!kid || k.kid === kid) && (!k.alg || k.alg === alg);
|
|
149
|
-
}
|
|
150
|
-
function _buildJWEHeader(alg, enc, key, userHeader, keyManagementParams, payload) {
|
|
151
|
-
const safeHeader = sanitizeObject(userHeader);
|
|
152
|
-
return applyTypCtyDefaults({
|
|
153
|
-
...isJWK(key) && key.kid ? { kid: key.kid } : {},
|
|
154
|
-
...safeHeader,
|
|
155
|
-
...keyManagementParams,
|
|
156
|
-
alg,
|
|
157
|
-
enc
|
|
158
|
-
}, payload);
|
|
159
|
-
}
|
|
160
|
-
//#endregion
|
|
161
|
-
export { JWTError, decrypt, encrypt, isJWTError };
|
|
1
|
+
import { D as JWTError, O as isJWTError } from "../_chunks/utils.mjs";
|
|
2
|
+
import { a as generalToFlattened, i as encryptMulti, n as encrypt, r as decryptMulti, t as decrypt } from "../_chunks/jwe.mjs";
|
|
3
|
+
export { JWTError, decrypt, decryptMulti, encrypt, encryptMulti, generalToFlattened, isJWTError };
|
package/dist/core/jwk.d.mts
CHANGED
|
@@ -1,24 +1,91 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { i as isJWTError, n as JWTErrorCauseMap, r as JWTErrorCode, t as JWTError } from "../_chunks/error.mjs";
|
|
3
|
-
|
|
4
|
-
//#region src/core/jwk.d.ts
|
|
1
|
+
import { $ as JWKAlgorithm, At as JWK_RSA_Public, Ct as JWK_Pair, Dt as JWK_RSA_ENC, Et as JWK_RSA, F as JWTErrorCauseMap, Ft as KeyManagementAlgorithm, G as DeriveKeyOptions, H as JoseHeaderParameters, I as JWTErrorCode, It as UnwrapKeyOptions, J as GenerateJWKReturn, K as DeriveKeyReturn, L as isJWTError, Lt as WrapKeyOptions, Mt as JWK_Symmetric, Nt as JWK_Symmetric_Algorithm, Ot as JWK_RSA_PSS, P as JWTError, Pt as JWK_oct, Q as JWK, Rt as WrapKeyResult, St as JWK_PBES2, Tt as JWK_Public, U as CompositeKey, W as ContentEncryptionAlgorithm, X as GenerateKeyOptions, Y as GenerateKeyAlgorithm, Z as GenerateKeyReturn, _t as JWK_HMAC, at as JWKSet, bt as JWK_OKP_Public, ct as JWK_AES_GCM_KW, dt as JWK_Asymmetric_Algorithm, et as JWKCacheAdapter, ft as JWK_EC, gt as JWK_EC_Public, ht as JWK_EC_Private, it as JWKParameters, jt as JWK_RSA_SIGN, kt as JWK_RSA_Private, lt as JWK_AES_KW, mt as JWK_ECDSA, nt as JWKLookupFunctionHeader, ot as JWK_AES_CBC_HMAC, pt as JWK_ECDH_ES, q as GenerateJWKOptions, rt as JWKPEMAlgorithm, st as JWK_AES_GCM, tt as JWKLookupFunction, ut as JWK_Asymmetric, vt as JWK_OKP, wt as JWK_Private, xt as JWK_OKP_SIGN, yt as JWK_OKP_Private } from "../_chunks/index.mjs";
|
|
5
2
|
/**
|
|
6
|
-
* Generates a cryptographic key for the specified algorithm.
|
|
3
|
+
* Generates a cryptographic key for the specified JWA algorithm.
|
|
7
4
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* The return type is narrowed by `alg` and `options.toJWK`. When `toJWK` is not set
|
|
6
|
+
* (or is `false`):
|
|
7
|
+
*
|
|
8
|
+
* - **Symmetric algorithms** (`HS*`, `A*KW`, `A*GCM`, `A*GCMKW`) → `CryptoKey`. The key
|
|
9
|
+
* is imported with Web Crypto usages derived from the algorithm (e.g. `["sign", "verify"]`
|
|
10
|
+
* for HMAC, `["wrapKey", "unwrapKey"]` for AES-KW, `["encrypt", "decrypt"]` for AES-GCM).
|
|
11
|
+
* - **AES-CBC + HMAC composites** (`A128CBC-HS256`, `A192CBC-HS384`, `A256CBC-HS512`) →
|
|
12
|
+
* `Uint8Array`. These keys are returned as raw bytes because the composite layout
|
|
13
|
+
* (AES key ∥ HMAC key) is not directly importable via `crypto.subtle.importKey`. They
|
|
14
|
+
* are split internally during encrypt/decrypt.
|
|
15
|
+
* - **Asymmetric algorithms** (`RS*`, `PS*`, `ES*`, `RSA-OAEP*`, `Ed25519`, `EdDSA`,
|
|
16
|
+
* `ECDH-ES*`) → `CryptoKeyPair`.
|
|
17
|
+
*
|
|
18
|
+
* When `options.toJWK` is `true`, the same call returns a JWK / JWK pair instead, with
|
|
19
|
+
* a freshly generated `kid` attached (use {@link generateJWK} to customise `kid`,
|
|
20
|
+
* `use`, etc.). Composite AES-CBC+HMAC keys are serialised to a single `JWK_oct` and
|
|
21
|
+
* re-split internally on use.
|
|
22
|
+
*
|
|
23
|
+
* PBES2 is not a key-generation algorithm — use {@link deriveKeyFromPassword} or
|
|
24
|
+
* {@link deriveJWKFromPassword} instead.
|
|
25
|
+
*
|
|
26
|
+
* @param alg The JWA algorithm identifier (e.g. `"HS256"`, `"RS256"`, `"A128GCM"`,
|
|
27
|
+
* `"A256CBC-HS512"`). PBES2, `"dir"`, and `"none"` are not accepted.
|
|
28
|
+
* @param options
|
|
29
|
+
* - `toJWK?` — when `true`, return JWK / JWK pair instead of `CryptoKey` / `CryptoKeyPair`.
|
|
30
|
+
* - `extractable?` — forwarded to `crypto.subtle.generateKey`. Defaults to `true`.
|
|
31
|
+
* - `keyUsage?` — override the default usages derived from `alg`.
|
|
32
|
+
* - `modulusLength?` — RSA only; defaults to `2048`.
|
|
33
|
+
* - `publicExponent?` — RSA only; defaults to `0x010001`.
|
|
34
|
+
* - `namedCurve?` — EC and OKP only; defaults to `"P-256"` for EC and `"Ed25519"` for OKP.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* // HS256 → CryptoKey
|
|
39
|
+
* const hmac = await generateKey("HS256");
|
|
40
|
+
*
|
|
41
|
+
* // A256CBC-HS512 → Uint8Array (composite key)
|
|
42
|
+
* const cek = await generateKey("A256CBC-HS512");
|
|
43
|
+
*
|
|
44
|
+
* // RS256 → CryptoKeyPair
|
|
45
|
+
* const rsa = await generateKey("RS256", { modulusLength: 2048 });
|
|
46
|
+
*
|
|
47
|
+
* // As JWK pair
|
|
48
|
+
* const { privateKey, publicKey } = await generateKey("ES256", { toJWK: true });
|
|
49
|
+
* ```
|
|
11
50
|
*/
|
|
12
51
|
declare function generateKey<TAlg extends GenerateKeyAlgorithm, TOptions extends GenerateKeyOptions>(alg: TAlg, options?: TOptions): Promise<GenerateKeyReturn<TAlg, TOptions>>;
|
|
13
52
|
/**
|
|
14
|
-
* Generates a
|
|
53
|
+
* Generates a ready-to-use JWK (or JWK pair) for the specified algorithm.
|
|
54
|
+
*
|
|
55
|
+
* Always returns JWK form with a `kid` attached — auto-generated via
|
|
56
|
+
* `crypto.randomUUID()` when not supplied. For a `CryptoKey` / `CryptoKeyPair`
|
|
57
|
+
* result instead, use {@link generateKey}. PBES2 is not a key-generation
|
|
58
|
+
* algorithm — use {@link deriveJWKFromPassword}.
|
|
59
|
+
*
|
|
60
|
+
* Composite AES-CBC+HMAC keys (`A128CBC-HS256`, `A192CBC-HS384`, `A256CBC-HS512`)
|
|
61
|
+
* are serialised to a single `JWK_oct` and re-split internally on use.
|
|
15
62
|
*
|
|
16
|
-
* @param alg The JWA algorithm identifier (e.g
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @
|
|
63
|
+
* @param alg The JWA algorithm identifier (e.g. `"HS256"`, `"RS256"`, `"ES256"`,
|
|
64
|
+
* `"A128GCM"`, `"A256CBC-HS512"`). PBES2, `"dir"`, and `"none"` are
|
|
65
|
+
* not accepted.
|
|
66
|
+
* @param options
|
|
67
|
+
* - `extractable?` — forwarded to `crypto.subtle.generateKey`. Defaults to `true`.
|
|
68
|
+
* - `keyUsage?` — override the default usages derived from `alg`.
|
|
69
|
+
* - `modulusLength?` — RSA only; defaults to `2048`.
|
|
70
|
+
* - `publicExponent?` — RSA only; defaults to `0x010001`.
|
|
71
|
+
* - `namedCurve?` — EC and OKP only; defaults to `"P-256"` for EC and `"Ed25519"` for OKP.
|
|
72
|
+
* - JWK metadata (`kid`, `use`, `x5c`, `x5t`, `x5t#S256`, `x5u`) is merged onto the
|
|
73
|
+
* result. `alg`, `kty`, `key_ops`, and `ext` are managed by the library and cannot
|
|
74
|
+
* be overridden here.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```ts
|
|
78
|
+
* // HS256 → JWK_oct
|
|
79
|
+
* const hmac = await generateJWK("HS256");
|
|
80
|
+
*
|
|
81
|
+
* // RS256 → { privateKey: JWK_RSA_Private; publicKey: JWK_RSA_Public }
|
|
82
|
+
* const rsa = await generateJWK("RS256", { modulusLength: 2048, kid: "rsa-1" });
|
|
83
|
+
*
|
|
84
|
+
* // ES256 with explicit metadata
|
|
85
|
+
* const { privateKey, publicKey } = await generateJWK("ES256", { kid: "ec-1", use: "sig" });
|
|
86
|
+
* ```
|
|
20
87
|
*/
|
|
21
|
-
declare function generateJWK<TAlg extends GenerateKeyAlgorithm>(alg: TAlg,
|
|
88
|
+
declare function generateJWK<TAlg extends GenerateKeyAlgorithm>(alg: TAlg, options?: GenerateJWKOptions & Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">): Promise<GenerateJWKReturn<TAlg>>;
|
|
22
89
|
/**
|
|
23
90
|
* Derives a key from a password using PBKDF2 as specified by PBES2 algorithms.
|
|
24
91
|
*
|
|
@@ -29,15 +96,25 @@ declare function generateJWK<TAlg extends GenerateKeyAlgorithm>(alg: TAlg, jwkPa
|
|
|
29
96
|
*/
|
|
30
97
|
declare function deriveKeyFromPassword<TAlg extends JWK_PBES2, TOptions extends DeriveKeyOptions>(password: string | Uint8Array<ArrayBuffer>, alg: TAlg, options: TOptions): Promise<DeriveKeyReturn<TOptions>>;
|
|
31
98
|
/**
|
|
32
|
-
* Derives a
|
|
99
|
+
* Derives a `JWK_oct` from a password using PBKDF2 as specified by PBES2
|
|
100
|
+
* (RFC 7518 §4.8). The resulting JWK's `alg` is the underlying AES-KW variant
|
|
101
|
+
* (`A128KW` / `A192KW` / `A256KW`), ready to use with {@link wrapKey} /
|
|
102
|
+
* {@link unwrapKey}.
|
|
33
103
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* @param
|
|
37
|
-
* @param
|
|
38
|
-
* @
|
|
104
|
+
* For a `CryptoKey` result without JWK metadata, use {@link deriveKeyFromPassword}.
|
|
105
|
+
*
|
|
106
|
+
* @param password The password to derive the key from (string or `Uint8Array`).
|
|
107
|
+
* @param alg The PBES2 algorithm identifier (e.g. `"PBES2-HS256+A128KW"`).
|
|
108
|
+
* @param options
|
|
109
|
+
* - `salt` — PBKDF2 salt input (`p2s`). Must be at least 8 octets (RFC 7518 §4.8.1.1).
|
|
110
|
+
* - `iterations` — PBKDF2 iteration count (`p2c`). Must be a positive integer.
|
|
111
|
+
* - `keyUsage?` — defaults to `["wrapKey", "unwrapKey"]`.
|
|
112
|
+
* - `extractable?` — forwarded to `crypto.subtle.importKey`. Defaults to `false`.
|
|
113
|
+
* - JWK metadata (`kid`, `use`, `x5c`, `x5t`, `x5t#S256`, `x5u`) is merged onto the
|
|
114
|
+
* result. `alg`, `kty`, `key_ops`, and `ext` are managed by the library and cannot
|
|
115
|
+
* be overridden here.
|
|
39
116
|
*/
|
|
40
|
-
declare function deriveJWKFromPassword(password: string | Uint8Array<ArrayBuffer>, alg: JWK_PBES2, options: Omit<DeriveKeyOptions, "toJWK"
|
|
117
|
+
declare function deriveJWKFromPassword(password: string | Uint8Array<ArrayBuffer>, alg: JWK_PBES2, options: Omit<DeriveKeyOptions, "toJWK"> & Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">): Promise<JWK_oct>;
|
|
41
118
|
/**
|
|
42
119
|
* Default JWK import cache backed by a WeakMap.
|
|
43
120
|
*
|
|
@@ -86,14 +163,21 @@ declare function clearJWKCache(): void;
|
|
|
86
163
|
/**
|
|
87
164
|
* Imports a key from various formats (CryptoKey, JWK, Uint8Array).
|
|
88
165
|
*
|
|
89
|
-
* - If `key` is a CryptoKey
|
|
90
|
-
* - If `key` is a Uint8Array
|
|
91
|
-
* - If `key` is a JWK_oct (symmetric key with
|
|
92
|
-
* - If `key` is any other JWK type (asymmetric),
|
|
166
|
+
* - If `key` is a `CryptoKey`, it's returned directly.
|
|
167
|
+
* - If `key` is a `Uint8Array`, it's returned directly.
|
|
168
|
+
* - If `key` is a `JWK_oct` (symmetric key with `k`), the raw key bytes are returned as `Uint8Array`.
|
|
169
|
+
* - If `key` is any other JWK type (asymmetric), an algorithm hint is required (positional or via options)
|
|
170
|
+
* and a `CryptoKey` is returned.
|
|
171
|
+
*
|
|
172
|
+
* ### `expect` option (asymmetric only)
|
|
173
|
+
*
|
|
174
|
+
* Pass `expect: "public"` or `expect: "private"` to validate the caller's intent against the key's
|
|
175
|
+
* shape before the import. A private JWK passed with `expect: "public"` throws `ERR_JWK_INVALID`
|
|
176
|
+
* instead of silently importing the private material. Callers who deliberately want to drop private
|
|
177
|
+
* fields can do so themselves — no silent stripping.
|
|
93
178
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* @returns A Promise resolving to the imported key as CryptoKey or Uint8Array.
|
|
179
|
+
* `expect` is a no-op for symmetric (`oct`) JWKs and for `CryptoKey` instances whose
|
|
180
|
+
* `algorithm.type` is `"secret"`.
|
|
97
181
|
*/
|
|
98
182
|
declare function importKey(key: string): Promise<Uint8Array<ArrayBuffer>>;
|
|
99
183
|
declare function importKey(key: Uint8Array<ArrayBuffer>): Promise<Uint8Array<ArrayBuffer>>;
|
|
@@ -105,6 +189,10 @@ declare function importKey(key: JWK_oct, options: {
|
|
|
105
189
|
usage: KeyUsage[]; /** Mark the key as extractable. Defaults to `false`. */
|
|
106
190
|
extractable?: boolean;
|
|
107
191
|
}): Promise<CryptoKey>;
|
|
192
|
+
declare function importKey(key: CryptoKey | JWK | Uint8Array<ArrayBuffer> | string, options: {
|
|
193
|
+
/** Algorithm hint. Required when `key.alg` is absent on an asymmetric JWK. */alg?: string; /** Reject on shape mismatch instead of silently importing. */
|
|
194
|
+
expect?: "public" | "private";
|
|
195
|
+
}): Promise<CryptoKey | Uint8Array<ArrayBuffer>>;
|
|
108
196
|
declare function importKey(key: CryptoKey | JWK | Uint8Array<ArrayBuffer> | string, alg?: string): Promise<CryptoKey | Uint8Array<ArrayBuffer>>;
|
|
109
197
|
/**
|
|
110
198
|
* Exports a CryptoKey to a JWK (JSON Web Key) format.
|
|
@@ -113,17 +201,19 @@ declare function importKey(key: CryptoKey | JWK | Uint8Array<ArrayBuffer> | stri
|
|
|
113
201
|
* @param jwk Optional partial JWK to merge with the exported key, allowing overrides.
|
|
114
202
|
* @returns A Promise resolving to the exported JWK.
|
|
115
203
|
*/
|
|
116
|
-
declare function exportKey<T extends JWK>(key: CryptoKey,
|
|
204
|
+
declare function exportKey<T extends JWK>(key: CryptoKey, jwkParams?: Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">): Promise<T>;
|
|
117
205
|
/**
|
|
118
206
|
* Wraps a Content Encryption Key (CEK) using the specified algorithm and wrapping key.
|
|
119
207
|
*
|
|
208
|
+
* The return shape is narrowed by `alg` — see {@link WrapKeyResult}.
|
|
209
|
+
*
|
|
120
210
|
* @param alg The JWA key management algorithm (e.g., "A128KW", "RSA-OAEP", "PBES2-HS256+A128KW").
|
|
121
211
|
* @param keyToWrap The key to be wrapped (CEK), typically a symmetric key as Uint8Array or CryptoKey.
|
|
122
212
|
* @param wrappingKey The key used to wrap the CEK (CryptoKey, JWK, or password string/Uint8Array for PBES2).
|
|
123
213
|
* @param options Additional options required by certain algorithms (e.g., p2s, p2c for PBES2).
|
|
124
|
-
* @returns A Promise resolving to an
|
|
214
|
+
* @returns A Promise resolving to an alg-specific {@link WrapKeyResult}.
|
|
125
215
|
*/
|
|
126
|
-
declare function wrapKey(alg:
|
|
216
|
+
declare function wrapKey<TAlg extends KeyManagementAlgorithm>(alg: TAlg, keyToWrap: CryptoKey | Uint8Array<ArrayBuffer>, wrappingKey: CryptoKey | JWK | string | Uint8Array<ArrayBuffer>, options?: WrapKeyOptions): Promise<WrapKeyResult<TAlg>>;
|
|
127
217
|
/**
|
|
128
218
|
* Unwraps a Content Encryption Key (CEK) using the specified algorithm and unwrapping key.
|
|
129
219
|
*
|
|
@@ -141,28 +231,95 @@ declare function unwrapKey(alg: KeyManagementAlgorithm, wrappedKey: Uint8Array<A
|
|
|
141
231
|
}): Promise<CryptoKey>;
|
|
142
232
|
declare function unwrapKey(alg: KeyManagementAlgorithm, wrappedKey: Uint8Array<ArrayBuffer>, unwrappingKey: CryptoKey | JWK | string | Uint8Array<ArrayBuffer>, options: UnwrapKeyOptions): Promise<CryptoKey | Uint8Array<ArrayBuffer>>;
|
|
143
233
|
/**
|
|
144
|
-
* Imports a
|
|
234
|
+
* Imports a PEM-encoded key and returns it as a JWK.
|
|
235
|
+
*
|
|
236
|
+
* The PEM type is inferred from the `-----BEGIN <X>-----` label:
|
|
237
|
+
* - `PRIVATE KEY` → PKCS#8 private key (RFC 5208)
|
|
238
|
+
* - `PUBLIC KEY` → SubjectPublicKeyInfo public key (RFC 5280 §4.1.2.7)
|
|
239
|
+
* - `CERTIFICATE` → X.509 certificate; its SPKI is extracted into the JWK and all cert metadata
|
|
240
|
+
* (issuer, validity, extensions) is discarded — a JWK cannot represent it
|
|
241
|
+
*
|
|
242
|
+
* A caller can override the inference via `options.pemType`; the underlying label assertion
|
|
243
|
+
* still runs, so a mismatched override (e.g. `pemType: "pkcs8"` on a SPKI body) throws
|
|
244
|
+
* `ERR_JWK_INVALID` before any crypto work.
|
|
145
245
|
*
|
|
146
246
|
* @param pem The PEM-encoded string.
|
|
147
|
-
* @param
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
247
|
+
* @param alg The JWA algorithm identifier. Required for `crypto.subtle.importKey` to understand
|
|
248
|
+
* the key's intended algorithm and for setting the `alg` field on the resulting JWK.
|
|
249
|
+
* @param options
|
|
250
|
+
* - `pemType?` — explicit PEM type; inferred from the label when omitted.
|
|
251
|
+
* - `extractable?` — forwarded to `crypto.subtle.importKey`. Defaults to `false` for private
|
|
252
|
+
* keys and `true` for public keys.
|
|
253
|
+
* - `jwkParams?` — additional JWK properties merged into the result (e.g. `kid`, `use`).
|
|
254
|
+
* `alg`, `kty`, `key_ops`, and `ext` are reserved and cannot be overridden here.
|
|
255
|
+
* @throws `JWTError("ERR_JWK_INVALID")` if the PEM type cannot be inferred (no recognised label
|
|
256
|
+
* and no `options.pemType`), or if the label does not match the requested/inferred type.
|
|
257
|
+
* @throws `JWTError("ERR_JWK_UNSUPPORTED")` if `options.pemType` is a value outside the supported set.
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```ts
|
|
261
|
+
* // Inferred — label on the PEM drives selection.
|
|
262
|
+
* const jwk = await importPEM(pemString, "RS256", { jwkParams: { kid: "rsa-1" } });
|
|
263
|
+
*
|
|
264
|
+
* // Explicit override.
|
|
265
|
+
* const jwk2 = await importPEM(pemString, "RS256", { pemType: "x509" });
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
declare function importPEM<T extends JWK>(pem: string, alg: JWKPEMAlgorithm, options?: {
|
|
269
|
+
/** PEM type. Inferred from the PEM label when omitted. */pemType?: "pkcs8" | "spki" | "x509"; /** Passed to `crypto.subtle.importKey`. Defaults to `false` for private keys, `true` otherwise. */
|
|
270
|
+
extractable?: boolean; /** Additional JWK properties merged into the exported key (e.g. `kid`). */
|
|
271
|
+
jwkParams?: Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">;
|
|
272
|
+
}): Promise<T>;
|
|
273
|
+
/**
|
|
274
|
+
* @deprecated Use {@link importPEM} instead. `pemType` has moved into the options object and
|
|
275
|
+
* is now inferred from the PEM label by default.
|
|
153
276
|
*/
|
|
154
277
|
declare function importFromPEM<T extends JWK>(pem: string, pemType: "pkcs8" | "spki" | "x509", alg: JWKPEMAlgorithm, options?: {
|
|
155
|
-
|
|
278
|
+
extractable?: boolean;
|
|
156
279
|
jwkParams?: Omit<JWKParameters, "alg" | "kty" | "key_ops" | "ext">;
|
|
157
280
|
}): Promise<T>;
|
|
158
281
|
/**
|
|
159
282
|
* Exports a JWK to a PEM-encoded string.
|
|
160
283
|
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
284
|
+
* The PEM format is inferred from the JWK shape:
|
|
285
|
+
* - JWK with `d` (private component) → PKCS#8 (`-----BEGIN PRIVATE KEY-----`)
|
|
286
|
+
* - JWK without `d` → SubjectPublicKeyInfo (`-----BEGIN PUBLIC KEY-----`)
|
|
287
|
+
*
|
|
288
|
+
* X.509 certificate export is intentionally not supported: a certificate carries metadata
|
|
289
|
+
* (subject/issuer DNs, validity window, extensions) and a CA signature that a JWK cannot provide.
|
|
290
|
+
* Producing a cert is a CA operation, not a key-format conversion.
|
|
291
|
+
*
|
|
292
|
+
* Symmetric `oct` JWKs cannot be exported to PEM — PKCS#8/SPKI are asymmetric-key formats.
|
|
293
|
+
*
|
|
294
|
+
* @param jwk The JWK to export. Must not be `kty: "oct"`.
|
|
295
|
+
* @param options
|
|
296
|
+
* - `pemFormat?` — force the output format. Inferred from the JWK shape when omitted.
|
|
297
|
+
* - `alg?` — algorithm hint used only when `jwk.alg` is absent (both `kty: "RSA"` / `"EC"` /
|
|
298
|
+
* `"OKP"` JWKs need an algorithm to be round-tripped through `crypto.subtle.importKey`).
|
|
299
|
+
* @throws `JWTError("ERR_JWK_UNSUPPORTED")` for `oct` JWKs, or an unrecognised `pemFormat`.
|
|
300
|
+
* @throws `JWTError("ERR_JWK_INVALID")` if the JWK requires an `alg` hint that was not supplied,
|
|
301
|
+
* or if `pemFormat` is forced to a value incompatible with the JWK's public/private shape.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```ts
|
|
305
|
+
* // Inferred — private JWKs become PKCS#8, public JWKs become SPKI.
|
|
306
|
+
* const pem = await exportPEM(jwk);
|
|
307
|
+
*
|
|
308
|
+
* // Override (will throw if incompatible with the JWK shape).
|
|
309
|
+
* const spki = await exportPEM(jwk, { pemFormat: "spki" });
|
|
310
|
+
*
|
|
311
|
+
* // JWK without `alg` — provide a hint.
|
|
312
|
+
* const pem2 = await exportPEM(rawJwk, { alg: "RS256" });
|
|
313
|
+
* ```
|
|
314
|
+
*/
|
|
315
|
+
declare function exportPEM(jwk: JWK, options?: {
|
|
316
|
+
/** PEM format. Inferred from the JWK shape when omitted. */pemFormat?: "pkcs8" | "spki"; /** Algorithm hint used when `jwk.alg` is absent. */
|
|
317
|
+
alg?: JWKPEMAlgorithm;
|
|
318
|
+
}): Promise<string>;
|
|
319
|
+
/**
|
|
320
|
+
* @deprecated Use {@link exportPEM} instead. `pemFormat` has moved into the options object and
|
|
321
|
+
* is now inferred from the JWK shape by default. The `algForCryptoKeyImport` parameter has
|
|
322
|
+
* been renamed to `options.alg`.
|
|
166
323
|
*/
|
|
167
324
|
declare function exportToPEM(jwk: JWK, pemFormat: "pkcs8" | "spki", algForCryptoKeyImport?: JWKPEMAlgorithm): Promise<string>;
|
|
168
325
|
/**
|
|
@@ -227,5 +384,4 @@ declare function getJWKFromSet(jwkSet: JWKSet, kidOrProtectedHeader: string | (J
|
|
|
227
384
|
* @returns An array of matching JWKs.
|
|
228
385
|
*/
|
|
229
386
|
declare function getJWKsFromSet(jwkSet: JWKSet, filter?: (jwk: JWK) => boolean): JWK[];
|
|
230
|
-
|
|
231
|
-
export { CompositeKey, ContentEncryptionAlgorithm, DeriveKeyOptions, DeriveKeyReturn, GenerateJWKOptions, GenerateJWKReturn, GenerateKeyAlgorithm, GenerateKeyOptions, GenerateKeyReturn, JWK, JWKAlgorithm, JWKCacheAdapter, JWKLookupFunction, JWKLookupFunctionHeader, JWKPEMAlgorithm, JWKParameters, JWKSet, JWK_AES_CBC_HMAC, JWK_AES_GCM, JWK_AES_GCM_KW, JWK_AES_KW, JWK_Asymmetric, JWK_Asymmetric_Algorithm, JWK_EC, JWK_ECDH_ES, JWK_ECDSA, JWK_EC_Private, JWK_EC_Public, JWK_HMAC, JWK_OKP, JWK_OKP_Private, JWK_OKP_Public, JWK_OKP_SIGN, JWK_PBES2, JWK_Pair, JWK_Private, JWK_Public, JWK_RSA, JWK_RSA_ENC, JWK_RSA_PSS, JWK_RSA_Private, JWK_RSA_Public, JWK_RSA_SIGN, JWK_Symmetric, JWK_Symmetric_Algorithm, JWK_oct, JWTError, type JWTErrorCauseMap, type JWTErrorCode, KeyManagementAlgorithm, UnwrapKeyOptions, WeakMapJWKCache, WrapKeyOptions, WrapKeyResult, clearJWKCache, configureJWKCache, deriveJWKFromPassword, deriveKeyFromPassword, deriveSharedSecret, exportKey, exportToPEM, generateJWK, generateKey, getJWKFromSet, getJWKsFromSet, importFromPEM, importKey, isJWTError, unwrapKey, wrapKey };
|
|
387
|
+
export { CompositeKey, ContentEncryptionAlgorithm, DeriveKeyOptions, DeriveKeyReturn, GenerateJWKOptions, GenerateJWKReturn, GenerateKeyAlgorithm, GenerateKeyOptions, GenerateKeyReturn, JWK, JWKAlgorithm, JWKCacheAdapter, JWKLookupFunction, JWKLookupFunctionHeader, JWKPEMAlgorithm, JWKParameters, JWKSet, JWK_AES_CBC_HMAC, JWK_AES_GCM, JWK_AES_GCM_KW, JWK_AES_KW, JWK_Asymmetric, JWK_Asymmetric_Algorithm, JWK_EC, JWK_ECDH_ES, JWK_ECDSA, JWK_EC_Private, JWK_EC_Public, JWK_HMAC, JWK_OKP, JWK_OKP_Private, JWK_OKP_Public, JWK_OKP_SIGN, JWK_PBES2, JWK_Pair, JWK_Private, JWK_Public, JWK_RSA, JWK_RSA_ENC, JWK_RSA_PSS, JWK_RSA_Private, JWK_RSA_Public, JWK_RSA_SIGN, JWK_Symmetric, JWK_Symmetric_Algorithm, JWK_oct, JWTError, type JWTErrorCauseMap, type JWTErrorCode, KeyManagementAlgorithm, UnwrapKeyOptions, WeakMapJWKCache, WrapKeyOptions, WrapKeyResult, clearJWKCache, configureJWKCache, deriveJWKFromPassword, deriveKeyFromPassword, deriveSharedSecret, exportKey, exportPEM, exportToPEM, generateJWK, generateKey, getJWKFromSet, getJWKsFromSet, importFromPEM, importKey, importPEM, isJWTError, unwrapKey, wrapKey };
|