jose 5.2.1 → 5.2.3
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/dist/browser/jwe/compact/decrypt.js +3 -3
- package/dist/browser/jwe/flattened/decrypt.js +18 -14
- package/dist/browser/jwe/flattened/encrypt.js +9 -14
- package/dist/browser/jwks/remote.js +1 -1
- package/dist/browser/lib/aesgcmkw.js +6 -4
- package/dist/browser/lib/validate_crit.js +1 -1
- package/dist/browser/runtime/decrypt.js +7 -1
- package/dist/browser/runtime/encrypt.js +13 -5
- package/dist/node/cjs/jwe/compact/decrypt.js +3 -3
- package/dist/node/cjs/jwe/flattened/decrypt.js +18 -14
- package/dist/node/cjs/jwe/flattened/encrypt.js +9 -14
- package/dist/node/cjs/jwks/remote.js +1 -1
- package/dist/node/cjs/lib/aesgcmkw.js +6 -4
- package/dist/node/cjs/lib/validate_crit.js +1 -1
- package/dist/node/cjs/runtime/decrypt.js +6 -0
- package/dist/node/cjs/runtime/encrypt.js +9 -3
- package/dist/node/esm/jwe/compact/decrypt.js +3 -3
- package/dist/node/esm/jwe/flattened/decrypt.js +18 -14
- package/dist/node/esm/jwe/flattened/encrypt.js +9 -14
- package/dist/node/esm/jwks/remote.js +1 -1
- package/dist/node/esm/lib/aesgcmkw.js +6 -4
- package/dist/node/esm/lib/validate_crit.js +1 -1
- package/dist/node/esm/runtime/decrypt.js +7 -1
- package/dist/node/esm/runtime/encrypt.js +9 -3
- package/dist/types/key/import.d.ts +17 -4
- package/dist/types/types.d.ts +2 -2
- package/package.json +1 -1
|
@@ -14,9 +14,9 @@ export async function compactDecrypt(jwe, key, options) {
|
|
|
14
14
|
}
|
|
15
15
|
const decrypted = await flattenedDecrypt({
|
|
16
16
|
ciphertext,
|
|
17
|
-
iv:
|
|
18
|
-
protected: protectedHeader
|
|
19
|
-
tag:
|
|
17
|
+
iv: iv || undefined,
|
|
18
|
+
protected: protectedHeader,
|
|
19
|
+
tag: tag || undefined,
|
|
20
20
|
encrypted_key: encryptedKey || undefined,
|
|
21
21
|
}, key, options);
|
|
22
22
|
const result = { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader };
|
|
@@ -15,14 +15,14 @@ export async function flattenedDecrypt(jwe, key, options) {
|
|
|
15
15
|
if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) {
|
|
16
16
|
throw new JWEInvalid('JOSE Header missing');
|
|
17
17
|
}
|
|
18
|
-
if (typeof jwe.iv !== 'string') {
|
|
19
|
-
throw new JWEInvalid('JWE Initialization Vector
|
|
18
|
+
if (jwe.iv !== undefined && typeof jwe.iv !== 'string') {
|
|
19
|
+
throw new JWEInvalid('JWE Initialization Vector incorrect type');
|
|
20
20
|
}
|
|
21
21
|
if (typeof jwe.ciphertext !== 'string') {
|
|
22
22
|
throw new JWEInvalid('JWE Ciphertext missing or incorrect type');
|
|
23
23
|
}
|
|
24
|
-
if (typeof jwe.tag !== 'string') {
|
|
25
|
-
throw new JWEInvalid('JWE Authentication Tag
|
|
24
|
+
if (jwe.tag !== undefined && typeof jwe.tag !== 'string') {
|
|
25
|
+
throw new JWEInvalid('JWE Authentication Tag incorrect type');
|
|
26
26
|
}
|
|
27
27
|
if (jwe.protected !== undefined && typeof jwe.protected !== 'string') {
|
|
28
28
|
throw new JWEInvalid('JWE Protected Header incorrect type');
|
|
@@ -104,17 +104,21 @@ export async function flattenedDecrypt(jwe, key, options) {
|
|
|
104
104
|
}
|
|
105
105
|
let iv;
|
|
106
106
|
let tag;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
tag = base64url(jwe.tag);
|
|
107
|
+
if (jwe.iv !== undefined) {
|
|
108
|
+
try {
|
|
109
|
+
iv = base64url(jwe.iv);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
throw new JWEInvalid('Failed to base64url decode the iv');
|
|
113
|
+
}
|
|
115
114
|
}
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
if (jwe.tag !== undefined) {
|
|
116
|
+
try {
|
|
117
|
+
tag = base64url(jwe.tag);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
throw new JWEInvalid('Failed to base64url decode the tag');
|
|
121
|
+
}
|
|
118
122
|
}
|
|
119
123
|
const protectedHeader = encoder.encode(jwe.protected ?? '');
|
|
120
124
|
let additionalData;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { encode as base64url } from '../../runtime/base64url.js';
|
|
2
2
|
import encrypt from '../../runtime/encrypt.js';
|
|
3
|
-
import generateIv from '../../lib/iv.js';
|
|
4
3
|
import encryptKeyManagement from '../../lib/encrypt_key_management.js';
|
|
5
4
|
import { JOSENotSupported, JWEInvalid } from '../../util/errors.js';
|
|
6
5
|
import isDisjoint from '../../lib/is_disjoint.js';
|
|
@@ -84,15 +83,8 @@ export class FlattenedEncrypt {
|
|
|
84
83
|
throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid');
|
|
85
84
|
}
|
|
86
85
|
let encryptedKey;
|
|
87
|
-
if (alg === 'dir') {
|
|
88
|
-
|
|
89
|
-
throw new TypeError('setContentEncryptionKey cannot be called when using Direct Encryption');
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
else if (alg === 'ECDH-ES') {
|
|
93
|
-
if (this._cek) {
|
|
94
|
-
throw new TypeError('setContentEncryptionKey cannot be called when using Direct Key Agreement');
|
|
95
|
-
}
|
|
86
|
+
if (this._cek && (alg === 'dir' || alg === 'ECDH-ES')) {
|
|
87
|
+
throw new TypeError(`setContentEncryptionKey cannot be called with JWE "alg" (Algorithm) Header ${alg}`);
|
|
96
88
|
}
|
|
97
89
|
let cek;
|
|
98
90
|
{
|
|
@@ -117,7 +109,6 @@ export class FlattenedEncrypt {
|
|
|
117
109
|
}
|
|
118
110
|
}
|
|
119
111
|
}
|
|
120
|
-
this._iv || (this._iv = generateIv(enc));
|
|
121
112
|
let additionalData;
|
|
122
113
|
let protectedHeader;
|
|
123
114
|
let aadMember;
|
|
@@ -134,12 +125,16 @@ export class FlattenedEncrypt {
|
|
|
134
125
|
else {
|
|
135
126
|
additionalData = protectedHeader;
|
|
136
127
|
}
|
|
137
|
-
const { ciphertext, tag } = await encrypt(enc, this._plaintext, cek, this._iv, additionalData);
|
|
128
|
+
const { ciphertext, tag, iv } = await encrypt(enc, this._plaintext, cek, this._iv, additionalData);
|
|
138
129
|
const jwe = {
|
|
139
130
|
ciphertext: base64url(ciphertext),
|
|
140
|
-
iv: base64url(this._iv),
|
|
141
|
-
tag: base64url(tag),
|
|
142
131
|
};
|
|
132
|
+
if (iv) {
|
|
133
|
+
jwe.iv = base64url(iv);
|
|
134
|
+
}
|
|
135
|
+
if (tag) {
|
|
136
|
+
jwe.tag = base64url(tag);
|
|
137
|
+
}
|
|
143
138
|
if (encryptedKey) {
|
|
144
139
|
jwe.encrypted_key = base64url(encryptedKey);
|
|
145
140
|
}
|
|
@@ -9,7 +9,7 @@ function isCloudflareWorkers() {
|
|
|
9
9
|
let USER_AGENT;
|
|
10
10
|
if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
|
|
11
11
|
const NAME = 'jose';
|
|
12
|
-
const VERSION = 'v5.2.
|
|
12
|
+
const VERSION = 'v5.2.3';
|
|
13
13
|
USER_AGENT = `${NAME}/${VERSION}`;
|
|
14
14
|
}
|
|
15
15
|
class RemoteJWKSet extends LocalJWKSet {
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import encrypt from '../runtime/encrypt.js';
|
|
2
2
|
import decrypt from '../runtime/decrypt.js';
|
|
3
|
-
import generateIv from './iv.js';
|
|
4
3
|
import { encode as base64url } from '../runtime/base64url.js';
|
|
5
4
|
export async function wrap(alg, key, cek, iv) {
|
|
6
5
|
const jweAlgorithm = alg.slice(0, 7);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const wrapped = await encrypt(jweAlgorithm, cek, key, iv, new Uint8Array(0));
|
|
7
|
+
return {
|
|
8
|
+
encryptedKey: wrapped.ciphertext,
|
|
9
|
+
iv: base64url(wrapped.iv),
|
|
10
|
+
tag: base64url(wrapped.tag),
|
|
11
|
+
};
|
|
10
12
|
}
|
|
11
13
|
export async function unwrap(alg, key, encryptedKey, iv, tag) {
|
|
12
14
|
const jweAlgorithm = alg.slice(0, 7);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JOSENotSupported } from '../util/errors.js';
|
|
2
2
|
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
3
|
-
if (joseHeader.crit !== undefined && protectedHeader
|
|
3
|
+
if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) {
|
|
4
4
|
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|
5
5
|
}
|
|
6
6
|
if (!protectedHeader || protectedHeader.crit === undefined) {
|
|
@@ -2,7 +2,7 @@ import { concat, uint64be } from '../lib/buffer_utils.js';
|
|
|
2
2
|
import checkIvLength from '../lib/check_iv_length.js';
|
|
3
3
|
import checkCekLength from './check_cek_length.js';
|
|
4
4
|
import timingSafeEqual from './timing_safe_equal.js';
|
|
5
|
-
import { JOSENotSupported, JWEDecryptionFailed } from '../util/errors.js';
|
|
5
|
+
import { JOSENotSupported, JWEDecryptionFailed, JWEInvalid } from '../util/errors.js';
|
|
6
6
|
import crypto, { isCryptoKey } from './webcrypto.js';
|
|
7
7
|
import { checkEncCryptoKey } from '../lib/crypto_key.js';
|
|
8
8
|
import invalidKeyInput from '../lib/invalid_key_input.js';
|
|
@@ -64,6 +64,12 @@ const decrypt = async (enc, cek, ciphertext, iv, tag, aad) => {
|
|
|
64
64
|
if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) {
|
|
65
65
|
throw new TypeError(invalidKeyInput(cek, ...types, 'Uint8Array'));
|
|
66
66
|
}
|
|
67
|
+
if (!iv) {
|
|
68
|
+
throw new JWEInvalid('JWE Initialization Vector missing');
|
|
69
|
+
}
|
|
70
|
+
if (!tag) {
|
|
71
|
+
throw new JWEInvalid('JWE Authentication Tag missing');
|
|
72
|
+
}
|
|
67
73
|
checkIvLength(enc, iv);
|
|
68
74
|
switch (enc) {
|
|
69
75
|
case 'A128CBC-HS256':
|
|
@@ -4,6 +4,7 @@ import checkCekLength from './check_cek_length.js';
|
|
|
4
4
|
import crypto, { isCryptoKey } from './webcrypto.js';
|
|
5
5
|
import { checkEncCryptoKey } from '../lib/crypto_key.js';
|
|
6
6
|
import invalidKeyInput from '../lib/invalid_key_input.js';
|
|
7
|
+
import generateIv from '../lib/iv.js';
|
|
7
8
|
import { JOSENotSupported } from '../util/errors.js';
|
|
8
9
|
import { types } from './is_key_like.js';
|
|
9
10
|
async function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
@@ -22,7 +23,7 @@ async function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
22
23
|
}, encKey, plaintext));
|
|
23
24
|
const macData = concat(aad, iv, ciphertext, uint64be(aad.length << 3));
|
|
24
25
|
const tag = new Uint8Array((await crypto.subtle.sign('HMAC', macKey, macData)).slice(0, keySize >> 3));
|
|
25
|
-
return { ciphertext, tag };
|
|
26
|
+
return { ciphertext, tag, iv };
|
|
26
27
|
}
|
|
27
28
|
async function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
28
29
|
let encKey;
|
|
@@ -41,25 +42,32 @@ async function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
41
42
|
}, encKey, plaintext));
|
|
42
43
|
const tag = encrypted.slice(-16);
|
|
43
44
|
const ciphertext = encrypted.slice(0, -16);
|
|
44
|
-
return { ciphertext, tag };
|
|
45
|
+
return { ciphertext, tag, iv };
|
|
45
46
|
}
|
|
46
47
|
const encrypt = async (enc, plaintext, cek, iv, aad) => {
|
|
47
48
|
if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) {
|
|
48
49
|
throw new TypeError(invalidKeyInput(cek, ...types, 'Uint8Array'));
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
+
if (iv) {
|
|
52
|
+
checkIvLength(enc, iv);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
iv = generateIv(enc);
|
|
56
|
+
}
|
|
51
57
|
switch (enc) {
|
|
52
58
|
case 'A128CBC-HS256':
|
|
53
59
|
case 'A192CBC-HS384':
|
|
54
60
|
case 'A256CBC-HS512':
|
|
55
|
-
if (cek instanceof Uint8Array)
|
|
61
|
+
if (cek instanceof Uint8Array) {
|
|
56
62
|
checkCekLength(cek, parseInt(enc.slice(-3), 10));
|
|
63
|
+
}
|
|
57
64
|
return cbcEncrypt(enc, plaintext, cek, iv, aad);
|
|
58
65
|
case 'A128GCM':
|
|
59
66
|
case 'A192GCM':
|
|
60
67
|
case 'A256GCM':
|
|
61
|
-
if (cek instanceof Uint8Array)
|
|
68
|
+
if (cek instanceof Uint8Array) {
|
|
62
69
|
checkCekLength(cek, parseInt(enc.slice(1, 4), 10));
|
|
70
|
+
}
|
|
63
71
|
return gcmEncrypt(enc, plaintext, cek, iv, aad);
|
|
64
72
|
default:
|
|
65
73
|
throw new JOSENotSupported('Unsupported JWE Content Encryption Algorithm');
|
|
@@ -17,9 +17,9 @@ async function compactDecrypt(jwe, key, options) {
|
|
|
17
17
|
}
|
|
18
18
|
const decrypted = await (0, decrypt_js_1.flattenedDecrypt)({
|
|
19
19
|
ciphertext,
|
|
20
|
-
iv:
|
|
21
|
-
protected: protectedHeader
|
|
22
|
-
tag:
|
|
20
|
+
iv: iv || undefined,
|
|
21
|
+
protected: protectedHeader,
|
|
22
|
+
tag: tag || undefined,
|
|
23
23
|
encrypted_key: encryptedKey || undefined,
|
|
24
24
|
}, key, options);
|
|
25
25
|
const result = { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader };
|
|
@@ -18,14 +18,14 @@ async function flattenedDecrypt(jwe, key, options) {
|
|
|
18
18
|
if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) {
|
|
19
19
|
throw new errors_js_1.JWEInvalid('JOSE Header missing');
|
|
20
20
|
}
|
|
21
|
-
if (typeof jwe.iv !== 'string') {
|
|
22
|
-
throw new errors_js_1.JWEInvalid('JWE Initialization Vector
|
|
21
|
+
if (jwe.iv !== undefined && typeof jwe.iv !== 'string') {
|
|
22
|
+
throw new errors_js_1.JWEInvalid('JWE Initialization Vector incorrect type');
|
|
23
23
|
}
|
|
24
24
|
if (typeof jwe.ciphertext !== 'string') {
|
|
25
25
|
throw new errors_js_1.JWEInvalid('JWE Ciphertext missing or incorrect type');
|
|
26
26
|
}
|
|
27
|
-
if (typeof jwe.tag !== 'string') {
|
|
28
|
-
throw new errors_js_1.JWEInvalid('JWE Authentication Tag
|
|
27
|
+
if (jwe.tag !== undefined && typeof jwe.tag !== 'string') {
|
|
28
|
+
throw new errors_js_1.JWEInvalid('JWE Authentication Tag incorrect type');
|
|
29
29
|
}
|
|
30
30
|
if (jwe.protected !== undefined && typeof jwe.protected !== 'string') {
|
|
31
31
|
throw new errors_js_1.JWEInvalid('JWE Protected Header incorrect type');
|
|
@@ -107,17 +107,21 @@ async function flattenedDecrypt(jwe, key, options) {
|
|
|
107
107
|
}
|
|
108
108
|
let iv;
|
|
109
109
|
let tag;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
tag = (0, base64url_js_1.decode)(jwe.tag);
|
|
110
|
+
if (jwe.iv !== undefined) {
|
|
111
|
+
try {
|
|
112
|
+
iv = (0, base64url_js_1.decode)(jwe.iv);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
throw new errors_js_1.JWEInvalid('Failed to base64url decode the iv');
|
|
116
|
+
}
|
|
118
117
|
}
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
if (jwe.tag !== undefined) {
|
|
119
|
+
try {
|
|
120
|
+
tag = (0, base64url_js_1.decode)(jwe.tag);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
throw new errors_js_1.JWEInvalid('Failed to base64url decode the tag');
|
|
124
|
+
}
|
|
121
125
|
}
|
|
122
126
|
const protectedHeader = buffer_utils_js_1.encoder.encode(jwe.protected ?? '');
|
|
123
127
|
let additionalData;
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.FlattenedEncrypt = exports.unprotected = void 0;
|
|
4
4
|
const base64url_js_1 = require("../../runtime/base64url.js");
|
|
5
5
|
const encrypt_js_1 = require("../../runtime/encrypt.js");
|
|
6
|
-
const iv_js_1 = require("../../lib/iv.js");
|
|
7
6
|
const encrypt_key_management_js_1 = require("../../lib/encrypt_key_management.js");
|
|
8
7
|
const errors_js_1 = require("../../util/errors.js");
|
|
9
8
|
const is_disjoint_js_1 = require("../../lib/is_disjoint.js");
|
|
@@ -95,15 +94,8 @@ class FlattenedEncrypt {
|
|
|
95
94
|
throw new errors_js_1.JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid');
|
|
96
95
|
}
|
|
97
96
|
let encryptedKey;
|
|
98
|
-
if (alg === 'dir') {
|
|
99
|
-
|
|
100
|
-
throw new TypeError('setContentEncryptionKey cannot be called when using Direct Encryption');
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
else if (alg === 'ECDH-ES') {
|
|
104
|
-
if (this._cek) {
|
|
105
|
-
throw new TypeError('setContentEncryptionKey cannot be called when using Direct Key Agreement');
|
|
106
|
-
}
|
|
97
|
+
if (this._cek && (alg === 'dir' || alg === 'ECDH-ES')) {
|
|
98
|
+
throw new TypeError(`setContentEncryptionKey cannot be called with JWE "alg" (Algorithm) Header ${alg}`);
|
|
107
99
|
}
|
|
108
100
|
let cek;
|
|
109
101
|
{
|
|
@@ -128,7 +120,6 @@ class FlattenedEncrypt {
|
|
|
128
120
|
}
|
|
129
121
|
}
|
|
130
122
|
}
|
|
131
|
-
this._iv ||= (0, iv_js_1.default)(enc);
|
|
132
123
|
let additionalData;
|
|
133
124
|
let protectedHeader;
|
|
134
125
|
let aadMember;
|
|
@@ -145,12 +136,16 @@ class FlattenedEncrypt {
|
|
|
145
136
|
else {
|
|
146
137
|
additionalData = protectedHeader;
|
|
147
138
|
}
|
|
148
|
-
const { ciphertext, tag } = await (0, encrypt_js_1.default)(enc, this._plaintext, cek, this._iv, additionalData);
|
|
139
|
+
const { ciphertext, tag, iv } = await (0, encrypt_js_1.default)(enc, this._plaintext, cek, this._iv, additionalData);
|
|
149
140
|
const jwe = {
|
|
150
141
|
ciphertext: (0, base64url_js_1.encode)(ciphertext),
|
|
151
|
-
iv: (0, base64url_js_1.encode)(this._iv),
|
|
152
|
-
tag: (0, base64url_js_1.encode)(tag),
|
|
153
142
|
};
|
|
143
|
+
if (iv) {
|
|
144
|
+
jwe.iv = (0, base64url_js_1.encode)(iv);
|
|
145
|
+
}
|
|
146
|
+
if (tag) {
|
|
147
|
+
jwe.tag = (0, base64url_js_1.encode)(tag);
|
|
148
|
+
}
|
|
154
149
|
if (encryptedKey) {
|
|
155
150
|
jwe.encrypted_key = (0, base64url_js_1.encode)(encryptedKey);
|
|
156
151
|
}
|
|
@@ -12,7 +12,7 @@ function isCloudflareWorkers() {
|
|
|
12
12
|
let USER_AGENT;
|
|
13
13
|
if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
|
|
14
14
|
const NAME = 'jose';
|
|
15
|
-
const VERSION = 'v5.2.
|
|
15
|
+
const VERSION = 'v5.2.3';
|
|
16
16
|
USER_AGENT = `${NAME}/${VERSION}`;
|
|
17
17
|
}
|
|
18
18
|
class RemoteJWKSet extends local_js_1.LocalJWKSet {
|
|
@@ -3,13 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.unwrap = exports.wrap = void 0;
|
|
4
4
|
const encrypt_js_1 = require("../runtime/encrypt.js");
|
|
5
5
|
const decrypt_js_1 = require("../runtime/decrypt.js");
|
|
6
|
-
const iv_js_1 = require("./iv.js");
|
|
7
6
|
const base64url_js_1 = require("../runtime/base64url.js");
|
|
8
7
|
async function wrap(alg, key, cek, iv) {
|
|
9
8
|
const jweAlgorithm = alg.slice(0, 7);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
const wrapped = await (0, encrypt_js_1.default)(jweAlgorithm, cek, key, iv, new Uint8Array(0));
|
|
10
|
+
return {
|
|
11
|
+
encryptedKey: wrapped.ciphertext,
|
|
12
|
+
iv: (0, base64url_js_1.encode)(wrapped.iv),
|
|
13
|
+
tag: (0, base64url_js_1.encode)(wrapped.tag),
|
|
14
|
+
};
|
|
13
15
|
}
|
|
14
16
|
exports.wrap = wrap;
|
|
15
17
|
async function unwrap(alg, key, encryptedKey, iv, tag) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const errors_js_1 = require("../util/errors.js");
|
|
4
4
|
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
5
|
-
if (joseHeader.crit !== undefined && protectedHeader
|
|
5
|
+
if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) {
|
|
6
6
|
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|
7
7
|
}
|
|
8
8
|
if (!protectedHeader || protectedHeader.crit === undefined) {
|
|
@@ -79,6 +79,12 @@ const decrypt = (enc, cek, ciphertext, iv, tag, aad) => {
|
|
|
79
79
|
else {
|
|
80
80
|
throw new TypeError((0, invalid_key_input_js_1.default)(cek, ...is_key_like_js_1.types, 'Uint8Array'));
|
|
81
81
|
}
|
|
82
|
+
if (!iv) {
|
|
83
|
+
throw new errors_js_1.JWEInvalid('JWE Initialization Vector missing');
|
|
84
|
+
}
|
|
85
|
+
if (!tag) {
|
|
86
|
+
throw new errors_js_1.JWEInvalid('JWE Authentication Tag missing');
|
|
87
|
+
}
|
|
82
88
|
(0, check_cek_length_js_1.default)(enc, key);
|
|
83
89
|
(0, check_iv_length_js_1.default)(enc, iv);
|
|
84
90
|
switch (enc) {
|
|
@@ -9,6 +9,7 @@ const webcrypto_js_1 = require("./webcrypto.js");
|
|
|
9
9
|
const crypto_key_js_1 = require("../lib/crypto_key.js");
|
|
10
10
|
const is_key_object_js_1 = require("./is_key_object.js");
|
|
11
11
|
const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
12
|
+
const iv_js_1 = require("../lib/iv.js");
|
|
12
13
|
const errors_js_1 = require("../util/errors.js");
|
|
13
14
|
const ciphers_js_1 = require("./ciphers.js");
|
|
14
15
|
const is_key_like_js_1 = require("./is_key_like.js");
|
|
@@ -27,7 +28,7 @@ function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
27
28
|
const ciphertext = (0, buffer_utils_js_1.concat)(cipher.update(plaintext), cipher.final());
|
|
28
29
|
const macSize = parseInt(enc.slice(-3), 10);
|
|
29
30
|
const tag = (0, cbc_tag_js_1.default)(aad, iv, ciphertext, macSize, macKey, keySize);
|
|
30
|
-
return { ciphertext, tag };
|
|
31
|
+
return { ciphertext, tag, iv };
|
|
31
32
|
}
|
|
32
33
|
function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
33
34
|
const keySize = parseInt(enc.slice(1, 4), 10);
|
|
@@ -42,7 +43,7 @@ function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
42
43
|
const ciphertext = cipher.update(plaintext);
|
|
43
44
|
cipher.final();
|
|
44
45
|
const tag = cipher.getAuthTag();
|
|
45
|
-
return { ciphertext, tag };
|
|
46
|
+
return { ciphertext, tag, iv };
|
|
46
47
|
}
|
|
47
48
|
const encrypt = (enc, plaintext, cek, iv, aad) => {
|
|
48
49
|
let key;
|
|
@@ -57,7 +58,12 @@ const encrypt = (enc, plaintext, cek, iv, aad) => {
|
|
|
57
58
|
throw new TypeError((0, invalid_key_input_js_1.default)(cek, ...is_key_like_js_1.types, 'Uint8Array'));
|
|
58
59
|
}
|
|
59
60
|
(0, check_cek_length_js_1.default)(enc, key);
|
|
60
|
-
|
|
61
|
+
if (iv) {
|
|
62
|
+
(0, check_iv_length_js_1.default)(enc, iv);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
iv = (0, iv_js_1.default)(enc);
|
|
66
|
+
}
|
|
61
67
|
switch (enc) {
|
|
62
68
|
case 'A128CBC-HS256':
|
|
63
69
|
case 'A192CBC-HS384':
|
|
@@ -14,9 +14,9 @@ export async function compactDecrypt(jwe, key, options) {
|
|
|
14
14
|
}
|
|
15
15
|
const decrypted = await flattenedDecrypt({
|
|
16
16
|
ciphertext,
|
|
17
|
-
iv:
|
|
18
|
-
protected: protectedHeader
|
|
19
|
-
tag:
|
|
17
|
+
iv: iv || undefined,
|
|
18
|
+
protected: protectedHeader,
|
|
19
|
+
tag: tag || undefined,
|
|
20
20
|
encrypted_key: encryptedKey || undefined,
|
|
21
21
|
}, key, options);
|
|
22
22
|
const result = { plaintext: decrypted.plaintext, protectedHeader: decrypted.protectedHeader };
|
|
@@ -15,14 +15,14 @@ export async function flattenedDecrypt(jwe, key, options) {
|
|
|
15
15
|
if (jwe.protected === undefined && jwe.header === undefined && jwe.unprotected === undefined) {
|
|
16
16
|
throw new JWEInvalid('JOSE Header missing');
|
|
17
17
|
}
|
|
18
|
-
if (typeof jwe.iv !== 'string') {
|
|
19
|
-
throw new JWEInvalid('JWE Initialization Vector
|
|
18
|
+
if (jwe.iv !== undefined && typeof jwe.iv !== 'string') {
|
|
19
|
+
throw new JWEInvalid('JWE Initialization Vector incorrect type');
|
|
20
20
|
}
|
|
21
21
|
if (typeof jwe.ciphertext !== 'string') {
|
|
22
22
|
throw new JWEInvalid('JWE Ciphertext missing or incorrect type');
|
|
23
23
|
}
|
|
24
|
-
if (typeof jwe.tag !== 'string') {
|
|
25
|
-
throw new JWEInvalid('JWE Authentication Tag
|
|
24
|
+
if (jwe.tag !== undefined && typeof jwe.tag !== 'string') {
|
|
25
|
+
throw new JWEInvalid('JWE Authentication Tag incorrect type');
|
|
26
26
|
}
|
|
27
27
|
if (jwe.protected !== undefined && typeof jwe.protected !== 'string') {
|
|
28
28
|
throw new JWEInvalid('JWE Protected Header incorrect type');
|
|
@@ -104,17 +104,21 @@ export async function flattenedDecrypt(jwe, key, options) {
|
|
|
104
104
|
}
|
|
105
105
|
let iv;
|
|
106
106
|
let tag;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
tag = base64url(jwe.tag);
|
|
107
|
+
if (jwe.iv !== undefined) {
|
|
108
|
+
try {
|
|
109
|
+
iv = base64url(jwe.iv);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
throw new JWEInvalid('Failed to base64url decode the iv');
|
|
113
|
+
}
|
|
115
114
|
}
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
if (jwe.tag !== undefined) {
|
|
116
|
+
try {
|
|
117
|
+
tag = base64url(jwe.tag);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
throw new JWEInvalid('Failed to base64url decode the tag');
|
|
121
|
+
}
|
|
118
122
|
}
|
|
119
123
|
const protectedHeader = encoder.encode(jwe.protected ?? '');
|
|
120
124
|
let additionalData;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { encode as base64url } from '../../runtime/base64url.js';
|
|
2
2
|
import encrypt from '../../runtime/encrypt.js';
|
|
3
|
-
import generateIv from '../../lib/iv.js';
|
|
4
3
|
import encryptKeyManagement from '../../lib/encrypt_key_management.js';
|
|
5
4
|
import { JOSENotSupported, JWEInvalid } from '../../util/errors.js';
|
|
6
5
|
import isDisjoint from '../../lib/is_disjoint.js';
|
|
@@ -92,15 +91,8 @@ export class FlattenedEncrypt {
|
|
|
92
91
|
throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid');
|
|
93
92
|
}
|
|
94
93
|
let encryptedKey;
|
|
95
|
-
if (alg === 'dir') {
|
|
96
|
-
|
|
97
|
-
throw new TypeError('setContentEncryptionKey cannot be called when using Direct Encryption');
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
else if (alg === 'ECDH-ES') {
|
|
101
|
-
if (this._cek) {
|
|
102
|
-
throw new TypeError('setContentEncryptionKey cannot be called when using Direct Key Agreement');
|
|
103
|
-
}
|
|
94
|
+
if (this._cek && (alg === 'dir' || alg === 'ECDH-ES')) {
|
|
95
|
+
throw new TypeError(`setContentEncryptionKey cannot be called with JWE "alg" (Algorithm) Header ${alg}`);
|
|
104
96
|
}
|
|
105
97
|
let cek;
|
|
106
98
|
{
|
|
@@ -125,7 +117,6 @@ export class FlattenedEncrypt {
|
|
|
125
117
|
}
|
|
126
118
|
}
|
|
127
119
|
}
|
|
128
|
-
this._iv ||= generateIv(enc);
|
|
129
120
|
let additionalData;
|
|
130
121
|
let protectedHeader;
|
|
131
122
|
let aadMember;
|
|
@@ -142,12 +133,16 @@ export class FlattenedEncrypt {
|
|
|
142
133
|
else {
|
|
143
134
|
additionalData = protectedHeader;
|
|
144
135
|
}
|
|
145
|
-
const { ciphertext, tag } = await encrypt(enc, this._plaintext, cek, this._iv, additionalData);
|
|
136
|
+
const { ciphertext, tag, iv } = await encrypt(enc, this._plaintext, cek, this._iv, additionalData);
|
|
146
137
|
const jwe = {
|
|
147
138
|
ciphertext: base64url(ciphertext),
|
|
148
|
-
iv: base64url(this._iv),
|
|
149
|
-
tag: base64url(tag),
|
|
150
139
|
};
|
|
140
|
+
if (iv) {
|
|
141
|
+
jwe.iv = base64url(iv);
|
|
142
|
+
}
|
|
143
|
+
if (tag) {
|
|
144
|
+
jwe.tag = base64url(tag);
|
|
145
|
+
}
|
|
151
146
|
if (encryptedKey) {
|
|
152
147
|
jwe.encrypted_key = base64url(encryptedKey);
|
|
153
148
|
}
|
|
@@ -9,7 +9,7 @@ function isCloudflareWorkers() {
|
|
|
9
9
|
let USER_AGENT;
|
|
10
10
|
if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
|
|
11
11
|
const NAME = 'jose';
|
|
12
|
-
const VERSION = 'v5.2.
|
|
12
|
+
const VERSION = 'v5.2.3';
|
|
13
13
|
USER_AGENT = `${NAME}/${VERSION}`;
|
|
14
14
|
}
|
|
15
15
|
class RemoteJWKSet extends LocalJWKSet {
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import encrypt from '../runtime/encrypt.js';
|
|
2
2
|
import decrypt from '../runtime/decrypt.js';
|
|
3
|
-
import generateIv from './iv.js';
|
|
4
3
|
import { encode as base64url } from '../runtime/base64url.js';
|
|
5
4
|
export async function wrap(alg, key, cek, iv) {
|
|
6
5
|
const jweAlgorithm = alg.slice(0, 7);
|
|
7
|
-
iv
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const wrapped = await encrypt(jweAlgorithm, cek, key, iv, new Uint8Array(0));
|
|
7
|
+
return {
|
|
8
|
+
encryptedKey: wrapped.ciphertext,
|
|
9
|
+
iv: base64url(wrapped.iv),
|
|
10
|
+
tag: base64url(wrapped.tag),
|
|
11
|
+
};
|
|
10
12
|
}
|
|
11
13
|
export async function unwrap(alg, key, encryptedKey, iv, tag) {
|
|
12
14
|
const jweAlgorithm = alg.slice(0, 7);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JOSENotSupported } from '../util/errors.js';
|
|
2
2
|
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
3
|
-
if (joseHeader.crit !== undefined && protectedHeader
|
|
3
|
+
if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) {
|
|
4
4
|
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|
5
5
|
}
|
|
6
6
|
if (!protectedHeader || protectedHeader.crit === undefined) {
|
|
@@ -2,7 +2,7 @@ import { createDecipheriv, KeyObject } from 'node:crypto';
|
|
|
2
2
|
import checkIvLength from '../lib/check_iv_length.js';
|
|
3
3
|
import checkCekLength from './check_cek_length.js';
|
|
4
4
|
import { concat } from '../lib/buffer_utils.js';
|
|
5
|
-
import { JOSENotSupported, JWEDecryptionFailed } from '../util/errors.js';
|
|
5
|
+
import { JOSENotSupported, JWEDecryptionFailed, JWEInvalid } from '../util/errors.js';
|
|
6
6
|
import timingSafeEqual from './timing_safe_equal.js';
|
|
7
7
|
import cbcTag from './cbc_tag.js';
|
|
8
8
|
import { isCryptoKey } from './webcrypto.js';
|
|
@@ -77,6 +77,12 @@ const decrypt = (enc, cek, ciphertext, iv, tag, aad) => {
|
|
|
77
77
|
else {
|
|
78
78
|
throw new TypeError(invalidKeyInput(cek, ...types, 'Uint8Array'));
|
|
79
79
|
}
|
|
80
|
+
if (!iv) {
|
|
81
|
+
throw new JWEInvalid('JWE Initialization Vector missing');
|
|
82
|
+
}
|
|
83
|
+
if (!tag) {
|
|
84
|
+
throw new JWEInvalid('JWE Authentication Tag missing');
|
|
85
|
+
}
|
|
80
86
|
checkCekLength(enc, key);
|
|
81
87
|
checkIvLength(enc, iv);
|
|
82
88
|
switch (enc) {
|
|
@@ -7,6 +7,7 @@ import { isCryptoKey } from './webcrypto.js';
|
|
|
7
7
|
import { checkEncCryptoKey } from '../lib/crypto_key.js';
|
|
8
8
|
import isKeyObject from './is_key_object.js';
|
|
9
9
|
import invalidKeyInput from '../lib/invalid_key_input.js';
|
|
10
|
+
import generateIv from '../lib/iv.js';
|
|
10
11
|
import { JOSENotSupported } from '../util/errors.js';
|
|
11
12
|
import supported from './ciphers.js';
|
|
12
13
|
import { types } from './is_key_like.js';
|
|
@@ -25,7 +26,7 @@ function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
25
26
|
const ciphertext = concat(cipher.update(plaintext), cipher.final());
|
|
26
27
|
const macSize = parseInt(enc.slice(-3), 10);
|
|
27
28
|
const tag = cbcTag(aad, iv, ciphertext, macSize, macKey, keySize);
|
|
28
|
-
return { ciphertext, tag };
|
|
29
|
+
return { ciphertext, tag, iv };
|
|
29
30
|
}
|
|
30
31
|
function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
31
32
|
const keySize = parseInt(enc.slice(1, 4), 10);
|
|
@@ -40,7 +41,7 @@ function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
40
41
|
const ciphertext = cipher.update(plaintext);
|
|
41
42
|
cipher.final();
|
|
42
43
|
const tag = cipher.getAuthTag();
|
|
43
|
-
return { ciphertext, tag };
|
|
44
|
+
return { ciphertext, tag, iv };
|
|
44
45
|
}
|
|
45
46
|
const encrypt = (enc, plaintext, cek, iv, aad) => {
|
|
46
47
|
let key;
|
|
@@ -55,7 +56,12 @@ const encrypt = (enc, plaintext, cek, iv, aad) => {
|
|
|
55
56
|
throw new TypeError(invalidKeyInput(cek, ...types, 'Uint8Array'));
|
|
56
57
|
}
|
|
57
58
|
checkCekLength(enc, key);
|
|
58
|
-
|
|
59
|
+
if (iv) {
|
|
60
|
+
checkIvLength(enc, iv);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
iv = generateIv(enc);
|
|
64
|
+
}
|
|
59
65
|
switch (enc) {
|
|
60
66
|
case 'A128CBC-HS256':
|
|
61
67
|
case 'A192CBC-HS384':
|
|
@@ -11,6 +11,10 @@ export interface PEMImportOptions {
|
|
|
11
11
|
* Imports a PEM-encoded SPKI string as a runtime-specific public key representation (KeyObject or
|
|
12
12
|
* CryptoKey).
|
|
13
13
|
*
|
|
14
|
+
* Note: The OID id-RSASSA-PSS (1.2.840.113549.1.1.10) is not supported in
|
|
15
|
+
* {@link https://w3c.github.io/webcrypto/ Web Cryptography API}, use the OID rsaEncryption
|
|
16
|
+
* (1.2.840.113549.1.1.1) instead for all RSA algorithms.
|
|
17
|
+
*
|
|
14
18
|
* @param spki PEM-encoded SPKI string
|
|
15
19
|
* @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used
|
|
16
20
|
* with the imported key, its presence is only enforced in Web Crypto API runtimes. See
|
|
@@ -21,6 +25,10 @@ export declare function importSPKI<KeyLikeType extends KeyLike = KeyLike>(spki:
|
|
|
21
25
|
* Imports the SPKI from an X.509 string certificate as a runtime-specific public key representation
|
|
22
26
|
* (KeyObject or CryptoKey).
|
|
23
27
|
*
|
|
28
|
+
* Note: The OID id-RSASSA-PSS (1.2.840.113549.1.1.10) is not supported in
|
|
29
|
+
* {@link https://w3c.github.io/webcrypto/ Web Cryptography API}, use the OID rsaEncryption
|
|
30
|
+
* (1.2.840.113549.1.1.1) instead for all RSA algorithms.
|
|
31
|
+
*
|
|
24
32
|
* @param x509 X.509 certificate string
|
|
25
33
|
* @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used
|
|
26
34
|
* with the imported key, its presence is only enforced in Web Crypto API runtimes. See
|
|
@@ -31,6 +39,10 @@ export declare function importX509<KeyLikeType extends KeyLike = KeyLike>(x509:
|
|
|
31
39
|
* Imports a PEM-encoded PKCS#8 string as a runtime-specific private key representation (KeyObject
|
|
32
40
|
* or CryptoKey).
|
|
33
41
|
*
|
|
42
|
+
* Note: The OID id-RSASSA-PSS (1.2.840.113549.1.1.10) is not supported in
|
|
43
|
+
* {@link https://w3c.github.io/webcrypto/ Web Cryptography API}, use the OID rsaEncryption
|
|
44
|
+
* (1.2.840.113549.1.1.1) instead for all RSA algorithms.
|
|
45
|
+
*
|
|
34
46
|
* @param pkcs8 PEM-encoded PKCS#8 string
|
|
35
47
|
* @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used
|
|
36
48
|
* with the imported key, its presence is only enforced in Web Crypto API runtimes. See
|
|
@@ -38,10 +50,11 @@ export declare function importX509<KeyLikeType extends KeyLike = KeyLike>(x509:
|
|
|
38
50
|
*/
|
|
39
51
|
export declare function importPKCS8<KeyLikeType extends KeyLike = KeyLike>(pkcs8: string, alg: string, options?: PEMImportOptions): Promise<KeyLikeType>;
|
|
40
52
|
/**
|
|
41
|
-
* Imports a JWK to a runtime-specific key representation (KeyLike). Either JWK "alg"
|
|
42
|
-
* Parameter
|
|
43
|
-
*
|
|
44
|
-
*
|
|
53
|
+
* Imports a JWK to a runtime-specific key representation (KeyLike). Either the JWK "alg"
|
|
54
|
+
* (Algorithm) Parameter, or the optional "alg" argument, must be present.
|
|
55
|
+
*
|
|
56
|
+
* Note: When the runtime is using {@link https://w3c.github.io/webcrypto/ Web Cryptography API} the
|
|
57
|
+
* jwk parameters "use", "key_ops", and "ext" are also used in the resulting `CryptoKey`.
|
|
45
58
|
*
|
|
46
59
|
* @param jwk JSON Web Key.
|
|
47
60
|
* @param alg (Only effective in Web Crypto API runtimes) JSON Web Algorithm identifier to be used
|
package/dist/types/types.d.ts
CHANGED
|
@@ -264,7 +264,7 @@ export interface FlattenedJWE {
|
|
|
264
264
|
* The "iv" member MUST be present and contain the value BASE64URL(JWE Initialization Vector) when
|
|
265
265
|
* the JWE Initialization Vector value is non-empty; otherwise, it MUST be absent.
|
|
266
266
|
*/
|
|
267
|
-
iv
|
|
267
|
+
iv?: string
|
|
268
268
|
|
|
269
269
|
/**
|
|
270
270
|
* The "protected" member MUST be present and contain the value BASE64URL(UTF8(JWE Protected
|
|
@@ -277,7 +277,7 @@ export interface FlattenedJWE {
|
|
|
277
277
|
* The "tag" member MUST be present and contain the value BASE64URL(JWE Authentication Tag) when
|
|
278
278
|
* the JWE Authentication Tag value is non-empty; otherwise, it MUST be absent.
|
|
279
279
|
*/
|
|
280
|
-
tag
|
|
280
|
+
tag?: string
|
|
281
281
|
|
|
282
282
|
/**
|
|
283
283
|
* The "unprotected" member MUST be present and contain the value JWE Shared Unprotected Header
|