jose 6.2.11 → 6.2.13
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 +2 -2
- package/dist/types/index.d.ts +1 -2
- package/dist/types/jwe/compact/decrypt.d.ts +9 -12
- package/dist/types/jwe/compact/encrypt.d.ts +14 -17
- package/dist/types/jwe/flattened/decrypt.d.ts +9 -12
- package/dist/types/jwe/flattened/encrypt.d.ts +17 -20
- package/dist/types/jwe/general/decrypt.d.ts +12 -17
- package/dist/types/jwe/general/encrypt.d.ts +19 -22
- package/dist/types/jwk/embedded.d.ts +3 -1
- package/dist/types/jwk/thumbprint.d.ts +4 -6
- package/dist/types/jwks/local.d.ts +5 -4
- package/dist/types/jwks/remote.d.ts +20 -21
- package/dist/types/jws/compact/sign.d.ts +7 -6
- package/dist/types/jws/compact/verify.d.ts +9 -12
- package/dist/types/jws/flattened/sign.d.ts +8 -7
- package/dist/types/jws/flattened/verify.d.ts +10 -12
- package/dist/types/jws/general/sign.d.ts +16 -17
- package/dist/types/jws/general/verify.d.ts +14 -18
- package/dist/types/jwt/decrypt.d.ts +15 -11
- package/dist/types/jwt/encrypt.d.ts +25 -23
- package/dist/types/jwt/sign.d.ts +4 -8
- package/dist/types/jwt/unsecured.d.ts +3 -7
- package/dist/types/jwt/verify.d.ts +12 -7
- package/dist/types/key/export.d.ts +6 -6
- package/dist/types/key/generate_key_pair.d.ts +9 -14
- package/dist/types/key/generate_secret.d.ts +10 -10
- package/dist/types/key/import.d.ts +21 -20
- package/dist/types/types.d.ts +217 -254
- package/dist/types/util/base64url.d.ts +7 -7
- package/dist/types/util/decode_jwt.d.ts +6 -1
- package/dist/types/util/decode_protected_header.d.ts +4 -3
- package/dist/types/util/errors.d.ts +30 -41
- package/dist/webapi/jwe/compact/decrypt.js +1 -2
- package/dist/webapi/jwe/compact/encrypt.js +9 -26
- package/dist/webapi/jwe/flattened/decrypt.js +3 -3
- package/dist/webapi/jwe/flattened/encrypt.js +11 -30
- package/dist/webapi/jwe/general/decrypt.js +6 -6
- package/dist/webapi/jwe/general/encrypt.js +36 -60
- package/dist/webapi/jwk/embedded.js +3 -4
- package/dist/webapi/jwk/thumbprint.js +11 -14
- package/dist/webapi/jwks/local.js +18 -11
- package/dist/webapi/jwks/remote.js +5 -5
- package/dist/webapi/jws/compact/sign.js +2 -4
- package/dist/webapi/jws/compact/verify.js +2 -2
- package/dist/webapi/jws/flattened/sign.js +8 -15
- package/dist/webapi/jws/flattened/verify.js +4 -14
- package/dist/webapi/jws/general/sign.js +6 -13
- package/dist/webapi/jws/general/verify.js +8 -10
- package/dist/webapi/jwt/decrypt.js +2 -3
- package/dist/webapi/jwt/encrypt.js +13 -27
- package/dist/webapi/jwt/sign.js +3 -3
- package/dist/webapi/jwt/unsecured.js +4 -5
- package/dist/webapi/jwt/verify.js +4 -4
- package/dist/webapi/key/export.js +12 -16
- package/dist/webapi/key/generate_key_pair.js +4 -13
- package/dist/webapi/key/generate_secret.js +5 -5
- package/dist/webapi/key/import.js +5 -9
- package/dist/webapi/lib/asn1.js +4 -6
- package/dist/webapi/lib/buffer_utils.js +39 -4
- package/dist/webapi/lib/content_encryption.js +29 -37
- package/dist/webapi/lib/deflate.js +9 -19
- package/dist/webapi/lib/jwe_algorithms.js +0 -4
- package/dist/webapi/lib/jwe_decrypt.js +30 -63
- package/dist/webapi/lib/jwe_encrypt.js +27 -60
- package/dist/webapi/lib/jws_algorithms.js +2 -2
- package/dist/webapi/lib/jws_sign.js +31 -45
- package/dist/webapi/lib/jws_verify.js +43 -48
- package/dist/webapi/lib/jwt_claims_set.js +45 -44
- package/dist/webapi/lib/key.js +122 -62
- package/dist/webapi/lib/key_management.js +57 -92
- package/dist/webapi/lib/{options.js → validate.js} +64 -3
- package/dist/webapi/util/base64url.js +5 -19
- package/dist/webapi/util/decode_jwt.js +13 -13
- package/dist/webapi/util/decode_protected_header.js +6 -6
- package/package.json +1 -1
- package/dist/webapi/lib/base64.js +0 -20
- package/dist/webapi/lib/crypto_key.js +0 -27
- package/dist/webapi/lib/helpers.js +0 -45
- package/dist/webapi/lib/invalid_key_input.js +0 -12
- package/dist/webapi/lib/is_key_like.js +0 -19
- package/dist/webapi/lib/jwk_metadata.js +0 -19
- package/dist/webapi/lib/jwk_to_key.js +0 -10
- package/dist/webapi/lib/key_options.js +0 -8
- package/dist/webapi/lib/signing.js +0 -22
- package/dist/webapi/lib/type_checks.js +0 -30
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const encoder = new TextEncoder(), decoder = new TextDecoder(), strictDecoder = new TextDecoder("utf-8", { fatal: !0 }),
|
|
1
|
+
const encoder = new TextEncoder(), decoder = new TextDecoder(), strictDecoder = new TextDecoder("utf-8", { fatal: !0 }), UINT32_RANGE = 2 ** 32;
|
|
2
2
|
function concat(...buffers) {
|
|
3
3
|
const size = buffers.reduce((acc, { length }) => acc + length, 0), buf = new Uint8Array(size);
|
|
4
4
|
let i = 0;
|
|
@@ -7,19 +7,25 @@ function concat(...buffers) {
|
|
|
7
7
|
return buf;
|
|
8
8
|
}
|
|
9
9
|
function writeUInt32BE(buf, value, offset) {
|
|
10
|
-
if (value < 0 || value >=
|
|
11
|
-
throw new RangeError(`value must be >= 0 and <= ${
|
|
10
|
+
if (value < 0 || value >= UINT32_RANGE)
|
|
11
|
+
throw new RangeError(`value must be >= 0 and <= ${UINT32_RANGE - 1}. Received ${value}`);
|
|
12
12
|
buf.set([value >>> 24, value >>> 16, value >>> 8, value & 255], offset);
|
|
13
13
|
}
|
|
14
14
|
function uint64be(value) {
|
|
15
|
-
const high = Math.floor(value /
|
|
15
|
+
const high = Math.floor(value / UINT32_RANGE), low = value % UINT32_RANGE, buf = new Uint8Array(8);
|
|
16
16
|
return writeUInt32BE(buf, high, 0), writeUInt32BE(buf, low, 4), buf;
|
|
17
17
|
}
|
|
18
18
|
function uint32be(value) {
|
|
19
19
|
const buf = new Uint8Array(4);
|
|
20
20
|
return writeUInt32BE(buf, value), buf;
|
|
21
21
|
}
|
|
22
|
+
const NON_ASCII = /[^\x00-\x7f]/;
|
|
22
23
|
function encode(string) {
|
|
24
|
+
if (typeof string == "string" && string.length >= 128) {
|
|
25
|
+
if (NON_ASCII.test(string))
|
|
26
|
+
throw new TypeError("non-ASCII string encountered in encode()");
|
|
27
|
+
return encoder.encode(string);
|
|
28
|
+
}
|
|
23
29
|
const bytes = new Uint8Array(string.length);
|
|
24
30
|
for (let i = 0; i < string.length; i++) {
|
|
25
31
|
const code = string.charCodeAt(i);
|
|
@@ -29,10 +35,39 @@ function encode(string) {
|
|
|
29
35
|
}
|
|
30
36
|
return bytes;
|
|
31
37
|
}
|
|
38
|
+
function encodeBase64(input, url = !1) {
|
|
39
|
+
if (Uint8Array.prototype.toBase64)
|
|
40
|
+
return input.toBase64({ alphabet: url ? "base64url" : "base64", omitPadding: url });
|
|
41
|
+
const CHUNK_SIZE = 32768, arr = [];
|
|
42
|
+
for (let i = 0; i < input.length; i += CHUNK_SIZE)
|
|
43
|
+
arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
|
|
44
|
+
const encoded = btoa(arr.join(""));
|
|
45
|
+
return url ? encoded.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_") : encoded;
|
|
46
|
+
}
|
|
47
|
+
function decodeBase64(encoded, url = !1) {
|
|
48
|
+
if (Uint8Array.fromBase64)
|
|
49
|
+
return Uint8Array.fromBase64(encoded, { alphabet: url ? "base64url" : "base64" });
|
|
50
|
+
if (url) {
|
|
51
|
+
if (encoded.includes("+") || encoded.includes("/"))
|
|
52
|
+
throw new TypeError("Invalid base64url");
|
|
53
|
+
encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
54
|
+
}
|
|
55
|
+
const binary = atob(encoded), bytes = new Uint8Array(binary.length);
|
|
56
|
+
for (let i = 0; i < binary.length; i++)
|
|
57
|
+
bytes[i] = binary.charCodeAt(i);
|
|
58
|
+
return bytes;
|
|
59
|
+
}
|
|
60
|
+
async function digest(algorithm, data) {
|
|
61
|
+
const subtleDigest = `SHA-${algorithm.slice(-3)}`;
|
|
62
|
+
return new Uint8Array(await crypto.subtle.digest(subtleDigest, data));
|
|
63
|
+
}
|
|
32
64
|
export {
|
|
33
65
|
concat,
|
|
66
|
+
decodeBase64,
|
|
34
67
|
decoder,
|
|
68
|
+
digest,
|
|
35
69
|
encode,
|
|
70
|
+
encodeBase64,
|
|
36
71
|
encoder,
|
|
37
72
|
strictDecoder,
|
|
38
73
|
uint32be,
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { concat, uint64be } from "./buffer_utils.js";
|
|
2
|
-
import {
|
|
3
|
-
import { invalidKeyInput } from "./invalid_key_input.js";
|
|
2
|
+
import { rawKey, invalidKeyInput, isCryptoKey } from "./key.js";
|
|
4
3
|
import { JWEDecryptionFailed, JWEInvalid } from "../util/errors.js";
|
|
5
|
-
import { isCryptoKey } from "./is_key_like.js";
|
|
6
4
|
const generateCek = (enc) => crypto.getRandomValues(new Uint8Array(enc.cekBits >> 3));
|
|
7
5
|
function checkCekLength(cek, expected) {
|
|
8
6
|
const actual = cek.byteLength << 3;
|
|
@@ -17,20 +15,20 @@ function checkIvLength(enc, iv) {
|
|
|
17
15
|
async function cbcKeySetup(enc, cek, usage) {
|
|
18
16
|
if (!(cek instanceof Uint8Array))
|
|
19
17
|
throw new TypeError(invalidKeyInput(cek, "Uint8Array"));
|
|
20
|
-
const
|
|
21
|
-
hash: `SHA-${
|
|
18
|
+
const keyLengthBits = enc.cekBits >> 1, encKey = await crypto.subtle.importKey("raw", cek.subarray(keyLengthBits >> 3), "AES-CBC", !1, [usage]), macKey = await crypto.subtle.importKey("raw", cek.subarray(0, keyLengthBits >> 3), {
|
|
19
|
+
hash: `SHA-${keyLengthBits << 1}`,
|
|
22
20
|
name: "HMAC"
|
|
23
21
|
}, !1, ["sign"]);
|
|
24
|
-
return [encKey, macKey,
|
|
22
|
+
return [encKey, macKey, keyLengthBits];
|
|
25
23
|
}
|
|
26
|
-
async function cbcHmacTag(macKey, macData,
|
|
27
|
-
return new Uint8Array((await crypto.subtle.sign("HMAC", macKey, macData)).slice(0,
|
|
24
|
+
async function cbcHmacTag(macKey, macData, keyLengthBits) {
|
|
25
|
+
return new Uint8Array((await crypto.subtle.sign("HMAC", macKey, macData)).slice(0, keyLengthBits >> 3));
|
|
28
26
|
}
|
|
29
27
|
async function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
30
|
-
const [encKey, macKey,
|
|
28
|
+
const [encKey, macKey, keyLengthBits] = await cbcKeySetup(enc, cek, "encrypt"), ciphertext = new Uint8Array(await crypto.subtle.encrypt({
|
|
31
29
|
iv,
|
|
32
30
|
name: "AES-CBC"
|
|
33
|
-
}, encKey, plaintext)), macData = concat(aad, iv, ciphertext,
|
|
31
|
+
}, encKey, plaintext)), al = uint64be(aad.length * 8), macData = concat(aad, iv, ciphertext, al), tag = await cbcHmacTag(macKey, macData, keyLengthBits);
|
|
34
32
|
return { ciphertext, tag, iv };
|
|
35
33
|
}
|
|
36
34
|
async function timingSafeEqual(a, b) {
|
|
@@ -38,7 +36,7 @@ async function timingSafeEqual(a, b) {
|
|
|
38
36
|
return crypto.subtle.verify(algorithm, key, aHmac, b);
|
|
39
37
|
}
|
|
40
38
|
async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
41
|
-
const [encKey, macKey,
|
|
39
|
+
const [encKey, macKey, keyLengthBits] = await cbcKeySetup(enc, cek, "decrypt"), al = uint64be(aad.length * 8), macData = concat(aad, iv, ciphertext, al), expectedTag = await cbcHmacTag(macKey, macData, keyLengthBits);
|
|
42
40
|
try {
|
|
43
41
|
if (await timingSafeEqual(tag, expectedTag))
|
|
44
42
|
return new Uint8Array(await crypto.subtle.decrypt({ iv, name: "AES-CBC" }, encKey, ciphertext));
|
|
@@ -46,21 +44,31 @@ async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
|
46
44
|
}
|
|
47
45
|
throw new JWEDecryptionFailed();
|
|
48
46
|
}
|
|
49
|
-
async function
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
47
|
+
async function encrypt(enc, plaintext, cek, iv, aad) {
|
|
48
|
+
if (!isCryptoKey(cek) && !(cek instanceof Uint8Array))
|
|
49
|
+
throw new TypeError(invalidKeyInput(cek, "CryptoKey", "KeyObject", "Uint8Array", "JSON Web Key"));
|
|
50
|
+
if (iv ? checkIvLength(enc, iv) : iv = generateIv(enc), cek instanceof Uint8Array && checkCekLength(cek, enc.cekBits), enc.cbc)
|
|
51
|
+
return cbcEncrypt(enc, plaintext, cek, iv, aad);
|
|
52
|
+
const encKey = await rawKey(cek, enc.subtle, "encrypt"), encrypted = new Uint8Array(await crypto.subtle.encrypt({
|
|
53
53
|
additionalData: aad,
|
|
54
54
|
iv,
|
|
55
55
|
name: "AES-GCM",
|
|
56
56
|
tagLength: 128
|
|
57
|
-
}, encKey, plaintext))
|
|
58
|
-
return { ciphertext: encrypted.
|
|
57
|
+
}, encKey, plaintext));
|
|
58
|
+
return { ciphertext: encrypted.subarray(0, -16), tag: encrypted.subarray(-16), iv };
|
|
59
59
|
}
|
|
60
|
-
async function
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
|
|
60
|
+
async function decrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
61
|
+
if (!isCryptoKey(cek) && !(cek instanceof Uint8Array))
|
|
62
|
+
throw new TypeError(invalidKeyInput(cek, "CryptoKey", "KeyObject", "Uint8Array", "JSON Web Key"));
|
|
63
|
+
if (!iv)
|
|
64
|
+
throw new JWEInvalid("JWE Initialization Vector missing");
|
|
65
|
+
if (!tag)
|
|
66
|
+
throw new JWEInvalid("JWE Authentication Tag missing");
|
|
67
|
+
if (!enc.cbc && tag.length !== 16)
|
|
68
|
+
throw new JWEInvalid("Invalid Authentication Tag length");
|
|
69
|
+
if (checkIvLength(enc, iv), cek instanceof Uint8Array && checkCekLength(cek, enc.cekBits), enc.cbc)
|
|
70
|
+
return cbcDecrypt(enc, cek, ciphertext, iv, tag, aad);
|
|
71
|
+
const encKey = await rawKey(cek, enc.subtle, "decrypt");
|
|
64
72
|
try {
|
|
65
73
|
return new Uint8Array(await crypto.subtle.decrypt({
|
|
66
74
|
additionalData: aad,
|
|
@@ -72,22 +80,6 @@ async function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
|
72
80
|
throw new JWEDecryptionFailed();
|
|
73
81
|
}
|
|
74
82
|
}
|
|
75
|
-
async function encrypt(enc, plaintext, cek, iv, aad) {
|
|
76
|
-
if (!isCryptoKey(cek) && !(cek instanceof Uint8Array))
|
|
77
|
-
throw new TypeError(invalidKeyInput(cek, "CryptoKey", "KeyObject", "Uint8Array", "JSON Web Key"));
|
|
78
|
-
return iv ? checkIvLength(enc, iv) : iv = generateIv(enc), cek instanceof Uint8Array && checkCekLength(cek, enc.cekBits), enc.cbc ? cbcEncrypt(enc, plaintext, cek, iv, aad) : gcmEncrypt(enc, plaintext, cek, iv, aad);
|
|
79
|
-
}
|
|
80
|
-
async function decrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
81
|
-
if (!isCryptoKey(cek) && !(cek instanceof Uint8Array))
|
|
82
|
-
throw new TypeError(invalidKeyInput(cek, "CryptoKey", "KeyObject", "Uint8Array", "JSON Web Key"));
|
|
83
|
-
if (!iv)
|
|
84
|
-
throw new JWEInvalid("JWE Initialization Vector missing");
|
|
85
|
-
if (!tag)
|
|
86
|
-
throw new JWEInvalid("JWE Authentication Tag missing");
|
|
87
|
-
if (!enc.cbc && tag.length !== 16)
|
|
88
|
-
throw new JWEInvalid("Invalid Authentication Tag length");
|
|
89
|
-
return checkIvLength(enc, iv), cek instanceof Uint8Array && checkCekLength(cek, enc.cekBits), enc.cbc ? cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) : gcmDecrypt(enc, cek, ciphertext, iv, tag, aad);
|
|
90
|
-
}
|
|
91
83
|
export {
|
|
92
84
|
checkCekLength,
|
|
93
85
|
checkIvLength,
|
|
@@ -10,30 +10,14 @@ function supported(name) {
|
|
|
10
10
|
if (typeof globalThis[name] > "u")
|
|
11
11
|
throw new JOSENotSupported(`JWE "zip" (Compression Algorithm) Header Parameter requires the ${name} API.`);
|
|
12
12
|
}
|
|
13
|
-
async function
|
|
14
|
-
|
|
15
|
-
const cs = new CompressionStream("deflate-raw"), writer = cs.writable.getWriter();
|
|
16
|
-
writer.write(input).catch(() => {
|
|
17
|
-
}), writer.close().catch(() => {
|
|
18
|
-
});
|
|
19
|
-
const chunks = [], reader = cs.readable.getReader();
|
|
20
|
-
for (; ; ) {
|
|
21
|
-
const { value, done } = await reader.read();
|
|
22
|
-
if (done)
|
|
23
|
-
break;
|
|
24
|
-
chunks.push(value);
|
|
25
|
-
}
|
|
26
|
-
return concat(...chunks);
|
|
27
|
-
}
|
|
28
|
-
async function decompress(input, maxLength) {
|
|
29
|
-
supported("DecompressionStream");
|
|
30
|
-
const ds = new DecompressionStream("deflate-raw"), writer = ds.writable.getWriter();
|
|
13
|
+
async function transform(stream, input, maxLength = 1 / 0) {
|
|
14
|
+
const writer = stream.writable.getWriter();
|
|
31
15
|
writer.write(input).catch(() => {
|
|
32
16
|
}), writer.close().catch(() => {
|
|
33
17
|
});
|
|
34
18
|
const chunks = [];
|
|
35
19
|
let length = 0;
|
|
36
|
-
const reader =
|
|
20
|
+
const reader = stream.readable.getReader();
|
|
37
21
|
for (; ; ) {
|
|
38
22
|
const { value, done } = await reader.read();
|
|
39
23
|
if (done)
|
|
@@ -43,6 +27,12 @@ async function decompress(input, maxLength) {
|
|
|
43
27
|
}
|
|
44
28
|
return concat(...chunks);
|
|
45
29
|
}
|
|
30
|
+
async function compress(input) {
|
|
31
|
+
return supported("CompressionStream"), transform(new CompressionStream("deflate-raw"), input);
|
|
32
|
+
}
|
|
33
|
+
async function decompress(input, maxLength) {
|
|
34
|
+
return supported("DecompressionStream"), transform(new DecompressionStream("deflate-raw"), input, maxLength);
|
|
35
|
+
}
|
|
46
36
|
export {
|
|
47
37
|
compress,
|
|
48
38
|
decompress,
|
|
@@ -105,15 +105,11 @@ function jweAlgorithm(alg) {
|
|
|
105
105
|
function isJWECEKTransport(algorithm) {
|
|
106
106
|
return algorithm.mode === "key-wrapping" || algorithm.mode === "key-encryption" || algorithm.mode === "key-agreement-with-key-wrapping";
|
|
107
107
|
}
|
|
108
|
-
function invalidJWEKeyManagementMode(_mode) {
|
|
109
|
-
throw new TypeError("Invalid JWE key management mode");
|
|
110
|
-
}
|
|
111
108
|
function jweEncryption(enc) {
|
|
112
109
|
return (typeof enc == "string" ? ENC[enc] : void 0) ?? unsupported("enc", "Encryption Algorithm");
|
|
113
110
|
}
|
|
114
111
|
export {
|
|
115
112
|
JWE,
|
|
116
|
-
invalidJWEKeyManagementMode,
|
|
117
113
|
isJWECEKTransport,
|
|
118
114
|
jweAlgorithm,
|
|
119
115
|
jweEncryption
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { decrypt, generateCek } from "./content_encryption.js";
|
|
2
|
-
import { decodeBase64url,
|
|
2
|
+
import { decodeBase64url, encodeAsciiMember, parseJoseHeader, isDisjoint, isObject, validateCrit, validateAlgorithms, JWE_RECOGNIZED } from "./validate.js";
|
|
3
3
|
import { JOSEAlgNotAllowed, JOSENotSupported, JWEInvalid } from "../util/errors.js";
|
|
4
|
-
import { isDisjoint, isObject } from "./type_checks.js";
|
|
5
4
|
import { decryptKeyManagement } from "./key_management.js";
|
|
6
|
-
import {
|
|
7
|
-
import { validateCrit, validateAlgorithms, JWE_RECOGNIZED } from "./options.js";
|
|
5
|
+
import { decoder } from "./buffer_utils.js";
|
|
8
6
|
import { prepareKey } from "./key.js";
|
|
9
|
-
import { JWE,
|
|
7
|
+
import { JWE, isJWECEKTransport, jweAlgorithm, jweEncryption } from "./jwe_algorithms.js";
|
|
10
8
|
import { decompress, validateZip } from "./deflate.js";
|
|
11
9
|
function snapshotSharedJWE(jwe) {
|
|
12
10
|
const { aad, ciphertext, iv, protected: encodedProtected, tag, unprotected } = jwe;
|
|
@@ -44,10 +42,6 @@ function snapshotRecipientJWE(recipient) {
|
|
|
44
42
|
]));
|
|
45
43
|
} else
|
|
46
44
|
header = inputHeader;
|
|
47
|
-
} catch (error) {
|
|
48
|
-
return [void 0, headerAlg, error];
|
|
49
|
-
}
|
|
50
|
-
try {
|
|
51
45
|
const { encrypted_key: encryptedKey } = recipient;
|
|
52
46
|
return [{ encrypted_key: encryptedKey, header }, headerAlg];
|
|
53
47
|
} catch (error) {
|
|
@@ -65,21 +59,15 @@ function checkRecipient(jwe) {
|
|
|
65
59
|
}
|
|
66
60
|
function shareJWE(jwe) {
|
|
67
61
|
const { protected: encodedProtected, ciphertext, iv, tag, aad } = jwe;
|
|
68
|
-
let
|
|
69
|
-
encodedProtected !== void 0 && (
|
|
70
|
-
|
|
71
|
-
return [
|
|
72
|
-
parsedProt,
|
|
62
|
+
let protectedHeader;
|
|
63
|
+
return encodedProtected !== void 0 && (protectedHeader = parseJoseHeader(encodedProtected, JWEInvalid, "JWE Protected Header is invalid")), [
|
|
64
|
+
protectedHeader,
|
|
73
65
|
decodeBase64url(ciphertext, "ciphertext", JWEInvalid),
|
|
74
66
|
iv !== void 0 ? decodeBase64url(iv, "iv", JWEInvalid) : void 0,
|
|
75
67
|
tag !== void 0 ? decodeBase64url(tag, "tag", JWEInvalid) : void 0,
|
|
76
|
-
aad !== void 0 ?
|
|
68
|
+
encodeAsciiMember((encodedProtected ?? "") + (aad !== void 0 ? `.${aad}` : ""), "aad", JWEInvalid)
|
|
77
69
|
];
|
|
78
70
|
}
|
|
79
|
-
function decryptResult(jwe, decrypted) {
|
|
80
|
-
const [plaintext, parsedProt, key, resolvedKey] = decrypted, { protected: encodedProtected, aad, unprotected, header } = jwe, result = { plaintext };
|
|
81
|
-
return encodedProtected !== void 0 && (result.protectedHeader = parsedProt), aad !== void 0 && (result.additionalAuthenticatedData = decodeBase64url(aad, "aad", JWEInvalid)), unprotected !== void 0 && (result.sharedUnprotectedHeader = unprotected), header !== void 0 && (result.unprotectedHeader = header), resolvedKey ? { ...result, key } : result;
|
|
82
|
-
}
|
|
83
71
|
function prepareDecrypt(options) {
|
|
84
72
|
return [
|
|
85
73
|
options && validateAlgorithms("keyManagementAlgorithms", options.keyManagementAlgorithms),
|
|
@@ -89,20 +77,17 @@ function prepareDecrypt(options) {
|
|
|
89
77
|
options?.maxDecompressedLength
|
|
90
78
|
];
|
|
91
79
|
}
|
|
92
|
-
async function
|
|
93
|
-
const [
|
|
80
|
+
async function decryptJWE(jwe, shared, key, token = shareJWE(jwe)) {
|
|
81
|
+
const [protectedHeader, ciphertext, iv, tag, additionalAuthenticatedData] = token, { header, unprotected, aad } = jwe;
|
|
94
82
|
let joseHeader;
|
|
95
83
|
if (header !== void 0 || unprotected !== void 0) {
|
|
96
|
-
if (!isDisjoint(
|
|
84
|
+
if (!isDisjoint(protectedHeader, header, unprotected))
|
|
97
85
|
throw new JWEInvalid("JWE Protected, JWE Unprotected Header, and JWE Per-Recipient Unprotected Header Parameter names must be disjoint");
|
|
98
|
-
joseHeader = { ...
|
|
86
|
+
joseHeader = { ...protectedHeader, ...header, ...unprotected };
|
|
99
87
|
} else
|
|
100
|
-
joseHeader =
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
async function decryptRecipientCore(jwe, token, shared, key, joseHeader) {
|
|
104
|
-
const [keyManagementAlgorithms, contentEncryptionAlgorithms, crit, maxPBES2Count, maxDecompressedLength] = shared, [parsedProt, ciphertext, iv, tag, additionalData] = token, { encrypted_key: encodedKey } = jwe;
|
|
105
|
-
validateCrit(JWEInvalid, JWE_RECOGNIZED, crit, parsedProt, joseHeader), validateZip(joseHeader, parsedProt);
|
|
88
|
+
joseHeader = protectedHeader ?? {};
|
|
89
|
+
const [keyManagementAlgorithms, contentEncryptionAlgorithms, crit, maxPBES2Count, maxDecompressedLength] = shared, { encrypted_key: encodedKey } = jwe;
|
|
90
|
+
validateCrit(JWEInvalid, JWE_RECOGNIZED, crit, protectedHeader, joseHeader), validateZip(joseHeader, protectedHeader);
|
|
106
91
|
const { alg, enc } = joseHeader;
|
|
107
92
|
if (typeof alg != "string" || !alg)
|
|
108
93
|
throw new JWEInvalid("missing JWE Algorithm (alg) in JWE Header");
|
|
@@ -137,28 +122,13 @@ async function decryptRecipientCore(jwe, token, shared, key, joseHeader) {
|
|
|
137
122
|
encryptedKey = new Uint8Array();
|
|
138
123
|
}
|
|
139
124
|
let resolvedKey = !1;
|
|
140
|
-
typeof key == "function" && (key = await key(
|
|
125
|
+
typeof key == "function" && (key = await key(protectedHeader, jwe), resolvedKey = !0);
|
|
141
126
|
const algEntry = selected ?? jweAlgorithm(alg);
|
|
142
127
|
isJWECEKTransport(algEntry) && encryptedKey === void 0 && (encryptedKey = new Uint8Array());
|
|
143
|
-
|
|
144
|
-
const mode = algEntry.mode;
|
|
145
|
-
switch (mode) {
|
|
146
|
-
case "direct-encryption":
|
|
147
|
-
k = await prepareKey(encEntry, key, "decrypt");
|
|
148
|
-
break;
|
|
149
|
-
case "direct-key-agreement":
|
|
150
|
-
case "key-wrapping":
|
|
151
|
-
case "key-encryption":
|
|
152
|
-
case "key-agreement-with-key-wrapping":
|
|
153
|
-
case "integrated-encryption":
|
|
154
|
-
k = await prepareKey(algEntry, key, "decrypt");
|
|
155
|
-
break;
|
|
156
|
-
default:
|
|
157
|
-
invalidJWEKeyManagementMode(mode);
|
|
158
|
-
}
|
|
128
|
+
const k = await prepareKey(algEntry.mode === "direct-encryption" ? encEntry : algEntry, key, "decrypt");
|
|
159
129
|
let plaintext;
|
|
160
130
|
if (algEntry.mode === "integrated-encryption")
|
|
161
|
-
plaintext = await algEntry.decrypt(k, encryptedKey, ciphertext,
|
|
131
|
+
plaintext = await algEntry.decrypt(k, encryptedKey, ciphertext, additionalAuthenticatedData, protectedHeader, joseHeader);
|
|
162
132
|
else {
|
|
163
133
|
const encryption = encEntry;
|
|
164
134
|
let cek;
|
|
@@ -169,7 +139,7 @@ async function decryptRecipientCore(jwe, token, shared, key, joseHeader) {
|
|
|
169
139
|
throw err;
|
|
170
140
|
cek = generateCek(encryption);
|
|
171
141
|
}
|
|
172
|
-
plaintext = await decrypt(encryption, cek, ciphertext, iv, tag,
|
|
142
|
+
plaintext = await decrypt(encryption, cek, ciphertext, iv, tag, additionalAuthenticatedData);
|
|
173
143
|
}
|
|
174
144
|
if (joseHeader.zip === "DEF") {
|
|
175
145
|
const decompressionLimit = maxDecompressedLength ?? 25e4;
|
|
@@ -181,10 +151,16 @@ async function decryptRecipientCore(jwe, token, shared, key, joseHeader) {
|
|
|
181
151
|
throw cause instanceof JWEInvalid ? cause : new JWEInvalid("Failed to decompress plaintext", { cause });
|
|
182
152
|
});
|
|
183
153
|
}
|
|
184
|
-
return
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
154
|
+
return {
|
|
155
|
+
plaintext,
|
|
156
|
+
...protectedHeader && { protectedHeader },
|
|
157
|
+
...aad !== void 0 && {
|
|
158
|
+
additionalAuthenticatedData: decodeBase64url(aad, "aad", JWEInvalid)
|
|
159
|
+
},
|
|
160
|
+
...unprotected && { sharedUnprotectedHeader: unprotected },
|
|
161
|
+
...header && { unprotectedHeader: header },
|
|
162
|
+
...resolvedKey && { key: k }
|
|
163
|
+
};
|
|
188
164
|
}
|
|
189
165
|
async function decryptCompact(jwe, shared, key) {
|
|
190
166
|
if (jwe instanceof Uint8Array && (jwe = decoder.decode(jwe)), typeof jwe != "string")
|
|
@@ -192,27 +168,18 @@ async function decryptCompact(jwe, shared, key) {
|
|
|
192
168
|
const { 0: protectedHeader, 1: encryptedKey, 2: iv, 3: ciphertext, 4: tag, length } = jwe.split(".");
|
|
193
169
|
if (length !== 5)
|
|
194
170
|
throw new JWEInvalid("Invalid Compact JWE");
|
|
195
|
-
|
|
171
|
+
return decryptJWE({
|
|
196
172
|
ciphertext,
|
|
197
173
|
iv: iv || void 0,
|
|
198
174
|
protected: protectedHeader,
|
|
199
175
|
tag: tag || void 0,
|
|
200
176
|
encrypted_key: encryptedKey || void 0
|
|
201
|
-
},
|
|
202
|
-
parsedProt,
|
|
203
|
-
decodeBase64url(ciphertext, "ciphertext", JWEInvalid),
|
|
204
|
-
iv ? decodeBase64url(iv, "iv", JWEInvalid) : void 0,
|
|
205
|
-
tag ? decodeBase64url(tag, "tag", JWEInvalid) : void 0,
|
|
206
|
-
protectedBytes
|
|
207
|
-
];
|
|
208
|
-
return decryptRecipientCore(flattened, token, shared, key, parsedProt);
|
|
177
|
+
}, shared, key);
|
|
209
178
|
}
|
|
210
179
|
export {
|
|
211
180
|
checkRecipient,
|
|
212
181
|
decryptCompact,
|
|
213
182
|
decryptJWE,
|
|
214
|
-
decryptRecipient,
|
|
215
|
-
decryptResult,
|
|
216
183
|
prepareDecrypt,
|
|
217
184
|
shareJWE,
|
|
218
185
|
snapshotRecipientJWE,
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { encode as b64u } from "../util/base64url.js";
|
|
2
|
-
import {
|
|
2
|
+
import { encrypt } from "./content_encryption.js";
|
|
3
3
|
import { encryptKeyManagement } from "./key_management.js";
|
|
4
4
|
import { JWEInvalid } from "../util/errors.js";
|
|
5
|
-
import { assertUint8Array, isDisjoint, isObject } from "./
|
|
6
|
-
import {
|
|
7
|
-
import { serializeJoseHeader, validateCrit, validateCritDuplicates, JWE_RECOGNIZED } from "./options.js";
|
|
5
|
+
import { assertUint8Array, isDisjoint, isObject, serializeJoseHeader, validateCrit, validateCritDuplicates, JWE_RECOGNIZED } from "./validate.js";
|
|
6
|
+
import { encode } from "./buffer_utils.js";
|
|
8
7
|
import { prepareKey } from "./key.js";
|
|
9
|
-
import { JWE,
|
|
8
|
+
import { JWE, jweAlgorithm, jweEncryption } from "./jwe_algorithms.js";
|
|
10
9
|
import { compress, validateZip } from "./deflate.js";
|
|
11
|
-
import { unprotected } from "./helpers.js";
|
|
12
10
|
function checkDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader) {
|
|
13
11
|
if (!isDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader))
|
|
14
12
|
throw new JWEInvalid("JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint");
|
|
15
13
|
}
|
|
16
|
-
function checkEncryptHeaders(input) {
|
|
14
|
+
function checkEncryptHeaders(input, options, sharedHeadersNormalized = !1) {
|
|
15
|
+
if (!input[1] && !input[2] && !input[3])
|
|
16
|
+
throw new JWEInvalid("either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()");
|
|
17
|
+
options !== void 0 && (input[8] = options?.crit);
|
|
17
18
|
let [, protectedHeader, unprotectedHeader, sharedUnprotectedHeader, aad, cek, iv, keyManagementParameters, crit] = input;
|
|
18
|
-
if (aad !== void 0 && assertUint8Array(aad, "JWE Additional Authenticated Data"), cek !== void 0 && assertUint8Array(cek, "JWE Content Encryption Key"), iv !== void 0 && assertUint8Array(iv, "JWE Initialization Vector"), protectedHeader !== void 0 && (protectedHeader = serializeJoseHeader(JWEInvalid, protectedHeader)[0], input[1] = protectedHeader), unprotectedHeader !== void 0 && (unprotectedHeader = serializeJoseHeader(JWEInvalid, unprotectedHeader)[0], input[2] = unprotectedHeader), sharedUnprotectedHeader !== void 0 && (sharedUnprotectedHeader = serializeJoseHeader(JWEInvalid, sharedUnprotectedHeader)[0], input[3] = sharedUnprotectedHeader), keyManagementParameters !== void 0 && !isObject(keyManagementParameters))
|
|
19
|
+
if (aad !== void 0 && assertUint8Array(aad, "JWE Additional Authenticated Data"), cek !== void 0 && assertUint8Array(cek, "JWE Content Encryption Key"), iv !== void 0 && assertUint8Array(iv, "JWE Initialization Vector"), !sharedHeadersNormalized && protectedHeader !== void 0 && (protectedHeader = serializeJoseHeader(JWEInvalid, protectedHeader)[0], input[1] = protectedHeader), unprotectedHeader !== void 0 && (unprotectedHeader = serializeJoseHeader(JWEInvalid, unprotectedHeader)[0], input[2] = unprotectedHeader), !sharedHeadersNormalized && sharedUnprotectedHeader !== void 0 && (sharedUnprotectedHeader = serializeJoseHeader(JWEInvalid, sharedUnprotectedHeader)[0], input[3] = sharedUnprotectedHeader), keyManagementParameters !== void 0 && !isObject(keyManagementParameters))
|
|
19
20
|
throw new TypeError("JWE Key Management Parameters must be an object");
|
|
20
21
|
checkDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader);
|
|
21
22
|
const joseHeader = {
|
|
@@ -27,82 +28,48 @@ function checkEncryptHeaders(input) {
|
|
|
27
28
|
const { alg, enc } = joseHeader;
|
|
28
29
|
if (typeof alg != "string" || !alg)
|
|
29
30
|
throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid');
|
|
30
|
-
|
|
31
|
+
const algEntry = JWE[alg];
|
|
32
|
+
if (algEntry?.mode === "integrated-encryption") {
|
|
31
33
|
if (enc !== void 0)
|
|
32
34
|
throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter must not be present for integrated encryption');
|
|
33
35
|
if (cek !== void 0)
|
|
34
36
|
throw new TypeError(`setContentEncryptionKey cannot be called with JWE "alg" (Algorithm) Header ${alg}`);
|
|
35
37
|
if (iv !== void 0)
|
|
36
38
|
throw new TypeError(`setInitializationVector cannot be called with JWE "alg" (Algorithm) Header ${alg}`);
|
|
37
|
-
return [joseHeader,
|
|
39
|
+
return [joseHeader, void 0, algEntry];
|
|
38
40
|
}
|
|
39
41
|
if (typeof enc != "string" || !enc)
|
|
40
42
|
throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid');
|
|
41
|
-
return [joseHeader,
|
|
42
|
-
}
|
|
43
|
-
function checkProducedEncryptedKey(encryptedKey) {
|
|
44
|
-
if (!(encryptedKey instanceof Uint8Array) || !encryptedKey.byteLength)
|
|
45
|
-
throw new TypeError("JWE key management algorithm did not produce an Encrypted Key");
|
|
46
|
-
}
|
|
47
|
-
async function transportCek(algEntry, encEntry, key, providedCek, joseHeader, providedParameters) {
|
|
48
|
-
const preparedKey = await prepareKey(algEntry, key, "encrypt"), cek = providedCek ?? generateCek(encEntry);
|
|
49
|
-
checkCekLength(cek, encEntry.cekBits);
|
|
50
|
-
const [, encryptedKey, parameters] = await encryptKeyManagement(algEntry, encEntry, preparedKey, joseHeader, cek, providedParameters);
|
|
51
|
-
return checkProducedEncryptedKey(encryptedKey), [cek, encryptedKey, parameters];
|
|
43
|
+
return [joseHeader, jweEncryption(enc), algEntry];
|
|
52
44
|
}
|
|
53
|
-
async function encryptJWE(input, checked, key
|
|
54
|
-
const [joseHeader,
|
|
45
|
+
async function encryptJWE(input, checked, key) {
|
|
46
|
+
const [joseHeader, encEntry, selected] = checked, [inputPlaintext, inputProtectedHeader, inputUnprotectedHeader, sharedUnprotectedHeader, aad, providedCek, inputIv, keyManagementParameters, , unprotectedParameters] = input;
|
|
55
47
|
let protectedHeader = inputProtectedHeader, unprotectedHeader = inputUnprotectedHeader;
|
|
56
|
-
const algEntry =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const mode = algEntry.mode;
|
|
61
|
-
switch (mode) {
|
|
62
|
-
case "direct-encryption":
|
|
63
|
-
cek = await prepareKey(encEntry, key, "encrypt");
|
|
64
|
-
break;
|
|
65
|
-
case "direct-key-agreement": {
|
|
66
|
-
const preparedKey = await prepareKey(algEntry, key, "encrypt");
|
|
67
|
-
[cek, , parameters] = await encryptKeyManagement(algEntry, encEntry, preparedKey, joseHeader, void 0, keyManagementParameters);
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
case "key-wrapping":
|
|
71
|
-
case "key-encryption":
|
|
72
|
-
case "key-agreement-with-key-wrapping":
|
|
73
|
-
[cek, encryptedKey, parameters] = await transportCek(algEntry, encEntry, key, providedCek, joseHeader, keyManagementParameters);
|
|
74
|
-
break;
|
|
75
|
-
case "integrated-encryption":
|
|
76
|
-
integratedKey = await prepareKey(algEntry, key, "encrypt");
|
|
77
|
-
break;
|
|
78
|
-
default:
|
|
79
|
-
invalidJWEKeyManagementMode(mode);
|
|
80
|
-
}
|
|
81
|
-
parameters && (unprotectedParameters ? unprotectedHeader = unprotectedHeader ? { ...unprotectedHeader, ...parameters } : parameters : protectedHeader = protectedHeader ? { ...protectedHeader, ...parameters } : parameters, checkDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader));
|
|
82
|
-
let protectedHeaderS, protectedHeaderB;
|
|
83
|
-
protectedHeader ? (protectedHeaderS = b64u(JSON.stringify(protectedHeader)), protectedHeaderB = encode(protectedHeaderS)) : (protectedHeaderS = "", protectedHeaderB = new Uint8Array());
|
|
84
|
-
let additionalData, aadMember;
|
|
85
|
-
aad?.byteLength ? (aadMember = b64u(aad), additionalData = concat(protectedHeaderB, encode("."), encode(aadMember))) : additionalData = protectedHeaderB;
|
|
48
|
+
const algEntry = selected ?? jweAlgorithm(joseHeader.alg);
|
|
49
|
+
let encryptedKey, parameters, cek;
|
|
50
|
+
algEntry.mode === "integrated-encryption" ? cek = await prepareKey(algEntry, key, "encrypt") : [cek, encryptedKey, parameters] = await encryptKeyManagement(algEntry, encEntry, key, joseHeader, providedCek, keyManagementParameters), parameters && (unprotectedParameters ? unprotectedHeader = unprotectedHeader ? { ...unprotectedHeader, ...parameters } : parameters : protectedHeader = protectedHeader ? { ...protectedHeader, ...parameters } : parameters, checkDisjoint(protectedHeader, unprotectedHeader, sharedUnprotectedHeader));
|
|
51
|
+
const encodedProtectedHeader = protectedHeader ? b64u(JSON.stringify(protectedHeader)) : "", encodedAad = aad?.byteLength ? b64u(aad) : void 0, additionalAuthenticatedData = encode(encodedAad ? `${encodedProtectedHeader}.${encodedAad}` : encodedProtectedHeader);
|
|
86
52
|
let plaintext = inputPlaintext;
|
|
87
53
|
joseHeader.zip === "DEF" && (plaintext = await compress(plaintext).catch((cause) => {
|
|
88
54
|
throw new JWEInvalid("Failed to compress plaintext", { cause });
|
|
89
55
|
}));
|
|
90
56
|
let ciphertext, tag, iv;
|
|
91
|
-
algEntry.mode === "integrated-encryption" ? [encryptedKey, ciphertext] = await algEntry.encrypt(
|
|
57
|
+
algEntry.mode === "integrated-encryption" ? [encryptedKey, ciphertext] = await algEntry.encrypt(cek, plaintext, additionalAuthenticatedData, protectedHeader, joseHeader, keyManagementParameters) : { ciphertext, tag, iv } = await encrypt(encEntry, plaintext, cek, inputIv, additionalAuthenticatedData);
|
|
92
58
|
const jwe = {
|
|
93
59
|
ciphertext: b64u(ciphertext)
|
|
94
60
|
};
|
|
95
|
-
return iv && (jwe.iv = b64u(iv)), tag && (jwe.tag = b64u(tag)), encryptedKey?.byteLength && (jwe.encrypted_key = b64u(encryptedKey)),
|
|
61
|
+
return iv && (jwe.iv = b64u(iv)), tag && (jwe.tag = b64u(tag)), encryptedKey?.byteLength && (jwe.encrypted_key = b64u(encryptedKey)), encodedAad && (jwe.aad = encodedAad), protectedHeader && (jwe.protected = encodedProtectedHeader), sharedUnprotectedHeader && (jwe.unprotected = sharedUnprotectedHeader), unprotectedHeader && (jwe.header = unprotectedHeader), jwe;
|
|
96
62
|
}
|
|
97
63
|
async function createJWE(input, key, options) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
64
|
+
return encryptJWE(input, checkEncryptHeaders(input, options), key);
|
|
65
|
+
}
|
|
66
|
+
function compactJWE(jwe) {
|
|
67
|
+
return [jwe.protected, jwe.encrypted_key, jwe.iv, jwe.ciphertext, jwe.tag].join(".");
|
|
101
68
|
}
|
|
102
69
|
export {
|
|
103
70
|
checkDisjoint,
|
|
104
71
|
checkEncryptHeaders,
|
|
72
|
+
compactJWE,
|
|
105
73
|
createJWE,
|
|
106
|
-
encryptJWE
|
|
107
|
-
transportCek
|
|
74
|
+
encryptJWE
|
|
108
75
|
};
|