jose 4.1.5 → 4.3.2
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 +16 -1
- package/dist/browser/index.js +1 -0
- package/dist/browser/jwe/flattened/encrypt.js +15 -4
- package/dist/browser/jwe/general/decrypt.js +3 -0
- package/dist/browser/jwe/general/encrypt.js +171 -0
- package/dist/browser/jwks/remote.js +16 -12
- package/dist/browser/jws/general/sign.js +25 -29
- package/dist/browser/lib/cek.js +5 -6
- package/dist/browser/lib/decrypt_key_management.js +1 -1
- package/dist/browser/lib/encrypt_key_management.js +1 -1
- package/dist/browser/lib/iv.js +4 -11
- package/dist/browser/runtime/aeskw.js +2 -1
- package/dist/browser/runtime/asn1.js +2 -1
- package/dist/browser/runtime/decrypt.js +2 -1
- package/dist/browser/runtime/ecdhes.js +5 -4
- package/dist/browser/runtime/encrypt.js +2 -1
- package/dist/browser/runtime/get_sign_verify_key.js +3 -2
- package/dist/browser/runtime/key_to_jwk.js +2 -1
- package/dist/browser/runtime/pbes2kw.js +2 -1
- package/dist/browser/runtime/rsaes.js +3 -2
- package/dist/node/cjs/index.js +9 -7
- package/dist/node/cjs/jwe/flattened/encrypt.js +16 -5
- package/dist/node/cjs/jwe/general/decrypt.js +3 -0
- package/dist/node/cjs/jwe/general/encrypt.js +175 -0
- package/dist/node/cjs/jwks/remote.js +16 -12
- package/dist/node/cjs/jws/general/sign.js +25 -29
- package/dist/node/cjs/lib/cek.js +5 -6
- package/dist/node/cjs/lib/decrypt_key_management.js +1 -1
- package/dist/node/cjs/lib/encrypt_key_management.js +1 -1
- package/dist/node/cjs/lib/iv.js +4 -11
- package/dist/node/cjs/runtime/aeskw.js +4 -3
- package/dist/node/cjs/runtime/asn1.js +2 -1
- package/dist/node/cjs/runtime/decrypt.js +5 -4
- package/dist/node/cjs/runtime/ecdhes.js +5 -4
- package/dist/node/cjs/runtime/encrypt.js +5 -4
- package/dist/node/cjs/runtime/get_named_curve.js +2 -1
- package/dist/node/cjs/runtime/get_sign_verify_key.js +3 -2
- package/dist/node/cjs/runtime/key_to_jwk.js +2 -1
- package/dist/node/cjs/runtime/pbes2kw.js +2 -1
- package/dist/node/cjs/runtime/rsaes.js +4 -3
- package/dist/node/esm/index.js +1 -0
- package/dist/node/esm/jwe/flattened/encrypt.js +15 -4
- package/dist/node/esm/jwe/general/decrypt.js +3 -0
- package/dist/node/esm/jwe/general/encrypt.js +171 -0
- package/dist/node/esm/jwks/remote.js +16 -12
- package/dist/node/esm/jws/general/sign.js +25 -29
- package/dist/node/esm/lib/cek.js +5 -6
- package/dist/node/esm/lib/decrypt_key_management.js +1 -1
- package/dist/node/esm/lib/encrypt_key_management.js +1 -1
- package/dist/node/esm/lib/iv.js +4 -11
- package/dist/node/esm/runtime/aeskw.js +4 -3
- package/dist/node/esm/runtime/asn1.js +2 -1
- package/dist/node/esm/runtime/decrypt.js +5 -4
- package/dist/node/esm/runtime/ecdhes.js +5 -4
- package/dist/node/esm/runtime/encrypt.js +5 -4
- package/dist/node/esm/runtime/get_named_curve.js +2 -1
- package/dist/node/esm/runtime/get_sign_verify_key.js +3 -2
- package/dist/node/esm/runtime/key_to_jwk.js +2 -1
- package/dist/node/esm/runtime/pbes2kw.js +2 -1
- package/dist/node/esm/runtime/rsaes.js +4 -3
- package/dist/types/index.d.ts +3 -1
- package/dist/types/jwe/compact/decrypt.d.ts +2 -2
- package/dist/types/jwe/compact/encrypt.d.ts +2 -2
- package/dist/types/jwe/flattened/encrypt.d.ts +1 -0
- package/dist/types/jwe/general/encrypt.d.ts +20 -0
- package/dist/types/jws/compact/sign.d.ts +2 -2
- package/dist/types/jws/compact/verify.d.ts +2 -2
- package/dist/types/jws/general/sign.d.ts +3 -0
- package/dist/types/jwt/decrypt.d.ts +2 -2
- package/dist/types/jwt/encrypt.d.ts +2 -2
- package/dist/types/jwt/sign.d.ts +2 -2
- package/dist/types/jwt/verify.d.ts +2 -2
- package/dist/types/types.d.ts +17 -14
- package/package.json +1 -1
|
@@ -11,8 +11,9 @@ const webcrypto_js_1 = require("./webcrypto.js");
|
|
|
11
11
|
const crypto_key_js_1 = require("../lib/crypto_key.js");
|
|
12
12
|
const is_key_object_js_1 = require("./is_key_object.js");
|
|
13
13
|
const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
14
|
+
const is_key_like_js_1 = require("./is_key_like.js");
|
|
14
15
|
const generateKeyPair = (0, util_1.promisify)(crypto_1.generateKeyPair);
|
|
15
|
-
const deriveKey =
|
|
16
|
+
const deriveKey = (publicKee, privateKee, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) => {
|
|
16
17
|
let publicKey;
|
|
17
18
|
if ((0, webcrypto_js_1.isCryptoKey)(publicKee)) {
|
|
18
19
|
(0, crypto_key_js_1.checkEncCryptoKey)(publicKee, 'ECDH-ES');
|
|
@@ -22,7 +23,7 @@ const deriveKey = async (publicKee, privateKee, algorithm, keyLength, apu = new
|
|
|
22
23
|
publicKey = publicKee;
|
|
23
24
|
}
|
|
24
25
|
else {
|
|
25
|
-
throw new TypeError((0, invalid_key_input_js_1.default)(publicKee,
|
|
26
|
+
throw new TypeError((0, invalid_key_input_js_1.default)(publicKee, ...is_key_like_js_1.types));
|
|
26
27
|
}
|
|
27
28
|
let privateKey;
|
|
28
29
|
if ((0, webcrypto_js_1.isCryptoKey)(privateKee)) {
|
|
@@ -33,7 +34,7 @@ const deriveKey = async (publicKee, privateKee, algorithm, keyLength, apu = new
|
|
|
33
34
|
privateKey = privateKee;
|
|
34
35
|
}
|
|
35
36
|
else {
|
|
36
|
-
throw new TypeError((0, invalid_key_input_js_1.default)(privateKee,
|
|
37
|
+
throw new TypeError((0, invalid_key_input_js_1.default)(privateKee, ...is_key_like_js_1.types));
|
|
37
38
|
}
|
|
38
39
|
const value = (0, buffer_utils_js_1.concat)((0, buffer_utils_js_1.lengthAndInput)(buffer_utils_js_1.encoder.encode(algorithm)), (0, buffer_utils_js_1.lengthAndInput)(apu), (0, buffer_utils_js_1.lengthAndInput)(apv), (0, buffer_utils_js_1.uint32be)(keyLength));
|
|
39
40
|
const sharedSecret = (0, crypto_1.diffieHellman)({ privateKey, publicKey });
|
|
@@ -49,7 +50,7 @@ const generateEpk = async (kee) => {
|
|
|
49
50
|
key = kee;
|
|
50
51
|
}
|
|
51
52
|
else {
|
|
52
|
-
throw new TypeError((0, invalid_key_input_js_1.default)(kee,
|
|
53
|
+
throw new TypeError((0, invalid_key_input_js_1.default)(kee, ...is_key_like_js_1.types));
|
|
53
54
|
}
|
|
54
55
|
switch (key.asymmetricKeyType) {
|
|
55
56
|
case 'x25519':
|
|
@@ -11,7 +11,8 @@ 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
12
|
const errors_js_1 = require("../util/errors.js");
|
|
13
13
|
const ciphers_js_1 = require("./ciphers.js");
|
|
14
|
-
|
|
14
|
+
const is_key_like_js_1 = require("./is_key_like.js");
|
|
15
|
+
function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
15
16
|
const keySize = parseInt(enc.substr(1, 3), 10);
|
|
16
17
|
if ((0, is_key_object_js_1.default)(cek)) {
|
|
17
18
|
cek = cek.export();
|
|
@@ -28,7 +29,7 @@ async function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
28
29
|
const tag = (0, cbc_tag_js_1.default)(aad, iv, ciphertext, macSize, macKey, keySize);
|
|
29
30
|
return { ciphertext, tag };
|
|
30
31
|
}
|
|
31
|
-
|
|
32
|
+
function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
32
33
|
const keySize = parseInt(enc.substr(1, 3), 10);
|
|
33
34
|
const algorithm = `aes-${keySize}-gcm`;
|
|
34
35
|
if (!(0, ciphers_js_1.default)(algorithm)) {
|
|
@@ -43,7 +44,7 @@ async function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
43
44
|
const tag = cipher.getAuthTag();
|
|
44
45
|
return { ciphertext, tag };
|
|
45
46
|
}
|
|
46
|
-
const encrypt =
|
|
47
|
+
const encrypt = (enc, plaintext, cek, iv, aad) => {
|
|
47
48
|
let key;
|
|
48
49
|
if ((0, webcrypto_js_1.isCryptoKey)(cek)) {
|
|
49
50
|
(0, crypto_key_js_1.checkEncCryptoKey)(cek, enc, 'encrypt');
|
|
@@ -53,7 +54,7 @@ const encrypt = async (enc, plaintext, cek, iv, aad) => {
|
|
|
53
54
|
key = cek;
|
|
54
55
|
}
|
|
55
56
|
else {
|
|
56
|
-
throw new TypeError((0, invalid_key_input_js_1.default)(cek,
|
|
57
|
+
throw new TypeError((0, invalid_key_input_js_1.default)(cek, ...is_key_like_js_1.types, 'Uint8Array'));
|
|
57
58
|
}
|
|
58
59
|
(0, check_cek_length_js_1.default)(enc, key);
|
|
59
60
|
(0, check_iv_length_js_1.default)(enc, iv);
|
|
@@ -7,6 +7,7 @@ const errors_js_1 = require("../util/errors.js");
|
|
|
7
7
|
const webcrypto_js_1 = require("./webcrypto.js");
|
|
8
8
|
const is_key_object_js_1 = require("./is_key_object.js");
|
|
9
9
|
const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
10
|
+
const is_key_like_js_1 = require("./is_key_like.js");
|
|
10
11
|
const p256 = buffer_1.Buffer.from([42, 134, 72, 206, 61, 3, 1, 7]);
|
|
11
12
|
const p384 = buffer_1.Buffer.from([43, 129, 4, 0, 34]);
|
|
12
13
|
const p521 = buffer_1.Buffer.from([43, 129, 4, 0, 35]);
|
|
@@ -36,7 +37,7 @@ const getNamedCurve = (kee, raw) => {
|
|
|
36
37
|
key = kee;
|
|
37
38
|
}
|
|
38
39
|
else {
|
|
39
|
-
throw new TypeError((0, invalid_key_input_js_1.default)(kee,
|
|
40
|
+
throw new TypeError((0, invalid_key_input_js_1.default)(kee, ...is_key_like_js_1.types));
|
|
40
41
|
}
|
|
41
42
|
if (key.type === 'secret') {
|
|
42
43
|
throw new TypeError('only "private" or "public" type keys can be used for this operation');
|
|
@@ -5,10 +5,11 @@ const webcrypto_js_1 = require("./webcrypto.js");
|
|
|
5
5
|
const crypto_key_js_1 = require("../lib/crypto_key.js");
|
|
6
6
|
const secret_key_js_1 = require("./secret_key.js");
|
|
7
7
|
const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
8
|
+
const is_key_like_js_1 = require("./is_key_like.js");
|
|
8
9
|
function getSignVerifyKey(alg, key, usage) {
|
|
9
10
|
if (key instanceof Uint8Array) {
|
|
10
11
|
if (!alg.startsWith('HS')) {
|
|
11
|
-
throw new TypeError((0, invalid_key_input_js_1.default)(key,
|
|
12
|
+
throw new TypeError((0, invalid_key_input_js_1.default)(key, ...is_key_like_js_1.types));
|
|
12
13
|
}
|
|
13
14
|
return (0, secret_key_js_1.default)(key);
|
|
14
15
|
}
|
|
@@ -19,6 +20,6 @@ function getSignVerifyKey(alg, key, usage) {
|
|
|
19
20
|
(0, crypto_key_js_1.checkSigCryptoKey)(key, alg, usage);
|
|
20
21
|
return crypto_1.KeyObject.from(key);
|
|
21
22
|
}
|
|
22
|
-
throw new TypeError((0, invalid_key_input_js_1.default)(key,
|
|
23
|
+
throw new TypeError((0, invalid_key_input_js_1.default)(key, ...is_key_like_js_1.types, 'Uint8Array'));
|
|
23
24
|
}
|
|
24
25
|
exports.default = getSignVerifyKey;
|
|
@@ -8,6 +8,7 @@ const get_named_curve_js_1 = require("./get_named_curve.js");
|
|
|
8
8
|
const webcrypto_js_1 = require("./webcrypto.js");
|
|
9
9
|
const is_key_object_js_1 = require("./is_key_object.js");
|
|
10
10
|
const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
11
|
+
const is_key_like_js_1 = require("./is_key_like.js");
|
|
11
12
|
const [major, minor] = process.version
|
|
12
13
|
.substr(1)
|
|
13
14
|
.split('.')
|
|
@@ -31,7 +32,7 @@ const keyToJWK = (key) => {
|
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
34
|
else {
|
|
34
|
-
throw new TypeError((0, invalid_key_input_js_1.default)(key,
|
|
35
|
+
throw new TypeError((0, invalid_key_input_js_1.default)(key, ...is_key_like_js_1.types, 'Uint8Array'));
|
|
35
36
|
}
|
|
36
37
|
if (jwkExportSupported) {
|
|
37
38
|
return keyObject.export({ format: 'jwk' });
|
|
@@ -12,6 +12,7 @@ const webcrypto_js_1 = require("./webcrypto.js");
|
|
|
12
12
|
const crypto_key_js_1 = require("../lib/crypto_key.js");
|
|
13
13
|
const is_key_object_js_1 = require("./is_key_object.js");
|
|
14
14
|
const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
15
|
+
const is_key_like_js_1 = require("./is_key_like.js");
|
|
15
16
|
const pbkdf2 = (0, util_1.promisify)(crypto_1.pbkdf2);
|
|
16
17
|
function getPassword(key, alg) {
|
|
17
18
|
if ((0, is_key_object_js_1.default)(key)) {
|
|
@@ -24,7 +25,7 @@ function getPassword(key, alg) {
|
|
|
24
25
|
(0, crypto_key_js_1.checkEncCryptoKey)(key, alg, 'deriveBits', 'deriveKey');
|
|
25
26
|
return crypto_1.KeyObject.from(key).export();
|
|
26
27
|
}
|
|
27
|
-
throw new TypeError((0, invalid_key_input_js_1.default)(key,
|
|
28
|
+
throw new TypeError((0, invalid_key_input_js_1.default)(key, ...is_key_like_js_1.types, 'Uint8Array'));
|
|
28
29
|
}
|
|
29
30
|
const encrypt = async (alg, key, cek, p2c = Math.floor(Math.random() * 2049) + 2048, p2s = (0, random_js_1.default)(new Uint8Array(16))) => {
|
|
30
31
|
(0, check_p2s_js_1.default)(p2s);
|
|
@@ -7,6 +7,7 @@ const webcrypto_js_1 = require("./webcrypto.js");
|
|
|
7
7
|
const crypto_key_js_1 = require("../lib/crypto_key.js");
|
|
8
8
|
const is_key_object_js_1 = require("./is_key_object.js");
|
|
9
9
|
const invalid_key_input_js_1 = require("../lib/invalid_key_input.js");
|
|
10
|
+
const is_key_like_js_1 = require("./is_key_like.js");
|
|
10
11
|
const checkKey = (key, alg) => {
|
|
11
12
|
if (key.asymmetricKeyType !== 'rsa') {
|
|
12
13
|
throw new TypeError('Invalid key for this operation, its asymmetricKeyType must be rsa');
|
|
@@ -48,9 +49,9 @@ function ensureKeyObject(key, alg, ...usages) {
|
|
|
48
49
|
(0, crypto_key_js_1.checkEncCryptoKey)(key, alg, ...usages);
|
|
49
50
|
return crypto_1.KeyObject.from(key);
|
|
50
51
|
}
|
|
51
|
-
throw new TypeError((0, invalid_key_input_js_1.default)(key,
|
|
52
|
+
throw new TypeError((0, invalid_key_input_js_1.default)(key, ...is_key_like_js_1.types));
|
|
52
53
|
}
|
|
53
|
-
const encrypt =
|
|
54
|
+
const encrypt = (alg, key, cek) => {
|
|
54
55
|
const padding = resolvePadding(alg);
|
|
55
56
|
const oaepHash = resolveOaepHash(alg);
|
|
56
57
|
const keyObject = ensureKeyObject(key, alg, 'wrapKey', 'encrypt');
|
|
@@ -58,7 +59,7 @@ const encrypt = async (alg, key, cek) => {
|
|
|
58
59
|
return (0, crypto_1.publicEncrypt)({ key: keyObject, oaepHash, padding }, cek);
|
|
59
60
|
};
|
|
60
61
|
exports.encrypt = encrypt;
|
|
61
|
-
const decrypt =
|
|
62
|
+
const decrypt = (alg, key, encryptedKey) => {
|
|
62
63
|
const padding = resolvePadding(alg);
|
|
63
64
|
const oaepHash = resolveOaepHash(alg);
|
|
64
65
|
const keyObject = ensureKeyObject(key, alg, 'unwrapKey', 'decrypt');
|
package/dist/node/esm/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { compactDecrypt } from './jwe/compact/decrypt.js';
|
|
2
2
|
export { flattenedDecrypt } from './jwe/flattened/decrypt.js';
|
|
3
3
|
export { generalDecrypt } from './jwe/general/decrypt.js';
|
|
4
|
+
export { GeneralEncrypt } from './jwe/general/encrypt.js';
|
|
4
5
|
export { compactVerify } from './jws/compact/verify.js';
|
|
5
6
|
export { flattenedVerify } from './jws/flattened/verify.js';
|
|
6
7
|
export { generalVerify } from './jws/general/verify.js';
|
|
@@ -7,6 +7,7 @@ import { JOSENotSupported, JWEInvalid } from '../../util/errors.js';
|
|
|
7
7
|
import isDisjoint from '../../lib/is_disjoint.js';
|
|
8
8
|
import { encoder, decoder, concat } from '../../lib/buffer_utils.js';
|
|
9
9
|
import validateCrit from '../../lib/validate_crit.js';
|
|
10
|
+
export const unprotected = Symbol();
|
|
10
11
|
export class FlattenedEncrypt {
|
|
11
12
|
constructor(plaintext) {
|
|
12
13
|
if (!(plaintext instanceof Uint8Array)) {
|
|
@@ -65,7 +66,7 @@ export class FlattenedEncrypt {
|
|
|
65
66
|
throw new JWEInvalid('either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt()');
|
|
66
67
|
}
|
|
67
68
|
if (!isDisjoint(this._protectedHeader, this._unprotectedHeader, this._sharedUnprotectedHeader)) {
|
|
68
|
-
throw new JWEInvalid('JWE
|
|
69
|
+
throw new JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint');
|
|
69
70
|
}
|
|
70
71
|
const joseHeader = {
|
|
71
72
|
...this._protectedHeader,
|
|
@@ -104,11 +105,21 @@ export class FlattenedEncrypt {
|
|
|
104
105
|
let parameters;
|
|
105
106
|
({ cek, encryptedKey, parameters } = await encryptKeyManagement(alg, enc, key, this._cek, this._keyManagementParameters));
|
|
106
107
|
if (parameters) {
|
|
107
|
-
if (
|
|
108
|
-
this.
|
|
108
|
+
if (options && unprotected in options) {
|
|
109
|
+
if (!this._unprotectedHeader) {
|
|
110
|
+
this.setUnprotectedHeader(parameters);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
this._unprotectedHeader = { ...this._unprotectedHeader, ...parameters };
|
|
114
|
+
}
|
|
109
115
|
}
|
|
110
116
|
else {
|
|
111
|
-
this._protectedHeader
|
|
117
|
+
if (!this._protectedHeader) {
|
|
118
|
+
this.setProtectedHeader(parameters);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
this._protectedHeader = { ...this._protectedHeader, ...parameters };
|
|
122
|
+
}
|
|
112
123
|
}
|
|
113
124
|
}
|
|
114
125
|
}
|
|
@@ -8,6 +8,9 @@ export async function generalDecrypt(jwe, key, options) {
|
|
|
8
8
|
if (!Array.isArray(jwe.recipients) || !jwe.recipients.every(isObject)) {
|
|
9
9
|
throw new JWEInvalid('JWE Recipients missing or incorrect type');
|
|
10
10
|
}
|
|
11
|
+
if (!jwe.recipients.length) {
|
|
12
|
+
throw new JWEInvalid('JWE Recipients has no members');
|
|
13
|
+
}
|
|
11
14
|
for (const recipient of jwe.recipients) {
|
|
12
15
|
try {
|
|
13
16
|
return await flattenedDecrypt({
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { FlattenedEncrypt, unprotected } from '../flattened/encrypt.js';
|
|
2
|
+
import { JWEInvalid } from '../../util/errors.js';
|
|
3
|
+
import generateCek from '../../lib/cek.js';
|
|
4
|
+
import isDisjoint from '../../lib/is_disjoint.js';
|
|
5
|
+
import encryptKeyManagement from '../../lib/encrypt_key_management.js';
|
|
6
|
+
import { encode as base64url } from '../../runtime/base64url.js';
|
|
7
|
+
import validateCrit from '../../lib/validate_crit.js';
|
|
8
|
+
class IndividualRecipient {
|
|
9
|
+
constructor(enc, key, options) {
|
|
10
|
+
this.parent = enc;
|
|
11
|
+
this.key = key;
|
|
12
|
+
this.options = options;
|
|
13
|
+
}
|
|
14
|
+
setUnprotectedHeader(unprotectedHeader) {
|
|
15
|
+
if (this.unprotectedHeader) {
|
|
16
|
+
throw new TypeError('setUnprotectedHeader can only be called once');
|
|
17
|
+
}
|
|
18
|
+
this.unprotectedHeader = unprotectedHeader;
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
addRecipient(...args) {
|
|
22
|
+
return this.parent.addRecipient(...args);
|
|
23
|
+
}
|
|
24
|
+
encrypt(...args) {
|
|
25
|
+
return this.parent.encrypt(...args);
|
|
26
|
+
}
|
|
27
|
+
done() {
|
|
28
|
+
return this.parent;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class GeneralEncrypt {
|
|
32
|
+
constructor(plaintext) {
|
|
33
|
+
this._recipients = [];
|
|
34
|
+
this._plaintext = plaintext;
|
|
35
|
+
}
|
|
36
|
+
addRecipient(key, options) {
|
|
37
|
+
const recipient = new IndividualRecipient(this, key, { crit: options === null || options === void 0 ? void 0 : options.crit });
|
|
38
|
+
this._recipients.push(recipient);
|
|
39
|
+
return recipient;
|
|
40
|
+
}
|
|
41
|
+
setProtectedHeader(protectedHeader) {
|
|
42
|
+
if (this._protectedHeader) {
|
|
43
|
+
throw new TypeError('setProtectedHeader can only be called once');
|
|
44
|
+
}
|
|
45
|
+
this._protectedHeader = protectedHeader;
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
setSharedUnprotectedHeader(sharedUnprotectedHeader) {
|
|
49
|
+
if (this._unprotectedHeader) {
|
|
50
|
+
throw new TypeError('setSharedUnprotectedHeader can only be called once');
|
|
51
|
+
}
|
|
52
|
+
this._unprotectedHeader = sharedUnprotectedHeader;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
setAdditionalAuthenticatedData(aad) {
|
|
56
|
+
this._aad = aad;
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
async encrypt(options) {
|
|
60
|
+
var _a, _b, _c;
|
|
61
|
+
if (!this._recipients.length) {
|
|
62
|
+
throw new JWEInvalid('at least one recipient must be added');
|
|
63
|
+
}
|
|
64
|
+
options = { deflateRaw: options === null || options === void 0 ? void 0 : options.deflateRaw };
|
|
65
|
+
if (this._recipients.length === 1) {
|
|
66
|
+
const [recipient] = this._recipients;
|
|
67
|
+
const flattened = await new FlattenedEncrypt(this._plaintext)
|
|
68
|
+
.setAdditionalAuthenticatedData(this._aad)
|
|
69
|
+
.setProtectedHeader(this._protectedHeader)
|
|
70
|
+
.setSharedUnprotectedHeader(this._unprotectedHeader)
|
|
71
|
+
.setUnprotectedHeader(recipient.unprotectedHeader)
|
|
72
|
+
.encrypt(recipient.key, { ...recipient.options, ...options });
|
|
73
|
+
let jwe = {
|
|
74
|
+
ciphertext: flattened.ciphertext,
|
|
75
|
+
iv: flattened.iv,
|
|
76
|
+
recipients: [{}],
|
|
77
|
+
tag: flattened.tag,
|
|
78
|
+
};
|
|
79
|
+
if (flattened.aad)
|
|
80
|
+
jwe.aad = flattened.aad;
|
|
81
|
+
if (flattened.protected)
|
|
82
|
+
jwe.protected = flattened.protected;
|
|
83
|
+
if (flattened.unprotected)
|
|
84
|
+
jwe.unprotected = flattened.unprotected;
|
|
85
|
+
if (flattened.encrypted_key)
|
|
86
|
+
jwe.recipients[0].encrypted_key = flattened.encrypted_key;
|
|
87
|
+
if (flattened.header)
|
|
88
|
+
jwe.recipients[0].header = flattened.header;
|
|
89
|
+
return jwe;
|
|
90
|
+
}
|
|
91
|
+
let enc;
|
|
92
|
+
for (let i = 0; i < this._recipients.length; i++) {
|
|
93
|
+
const recipient = this._recipients[i];
|
|
94
|
+
if (!isDisjoint(this._protectedHeader, this._unprotectedHeader, recipient.unprotectedHeader)) {
|
|
95
|
+
throw new JWEInvalid('JWE Protected, JWE Shared Unprotected and JWE Per-Recipient Header Parameter names must be disjoint');
|
|
96
|
+
}
|
|
97
|
+
const joseHeader = {
|
|
98
|
+
...this._protectedHeader,
|
|
99
|
+
...this._unprotectedHeader,
|
|
100
|
+
...recipient.unprotectedHeader,
|
|
101
|
+
};
|
|
102
|
+
const { alg } = joseHeader;
|
|
103
|
+
if (typeof alg !== 'string' || !alg) {
|
|
104
|
+
throw new JWEInvalid('JWE "alg" (Algorithm) Header Parameter missing or invalid');
|
|
105
|
+
}
|
|
106
|
+
if (alg === 'dir' || alg === 'ECDH-ES') {
|
|
107
|
+
throw new JWEInvalid('"dir" and "ECDH-ES" alg may only be used with a single recipient');
|
|
108
|
+
}
|
|
109
|
+
if (typeof joseHeader.enc !== 'string' || !joseHeader.enc) {
|
|
110
|
+
throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter missing or invalid');
|
|
111
|
+
}
|
|
112
|
+
if (!enc) {
|
|
113
|
+
enc = joseHeader.enc;
|
|
114
|
+
}
|
|
115
|
+
else if (enc !== joseHeader.enc) {
|
|
116
|
+
throw new JWEInvalid('JWE "enc" (Encryption Algorithm) Header Parameter must be the same for all recipients');
|
|
117
|
+
}
|
|
118
|
+
validateCrit(JWEInvalid, new Map(), recipient.options.crit, this._protectedHeader, joseHeader);
|
|
119
|
+
if (joseHeader.zip !== undefined) {
|
|
120
|
+
if (!this._protectedHeader || !this._protectedHeader.zip) {
|
|
121
|
+
throw new JWEInvalid('JWE "zip" (Compression Algorithm) Header MUST be integrity protected');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const cek = generateCek(enc);
|
|
126
|
+
let jwe = {
|
|
127
|
+
ciphertext: '',
|
|
128
|
+
iv: '',
|
|
129
|
+
recipients: [],
|
|
130
|
+
tag: '',
|
|
131
|
+
};
|
|
132
|
+
for (let i = 0; i < this._recipients.length; i++) {
|
|
133
|
+
const recipient = this._recipients[i];
|
|
134
|
+
const target = {};
|
|
135
|
+
jwe.recipients.push(target);
|
|
136
|
+
if (i === 0) {
|
|
137
|
+
const flattened = await new FlattenedEncrypt(this._plaintext)
|
|
138
|
+
.setAdditionalAuthenticatedData(this._aad)
|
|
139
|
+
.setContentEncryptionKey(cek)
|
|
140
|
+
.setProtectedHeader(this._protectedHeader)
|
|
141
|
+
.setSharedUnprotectedHeader(this._unprotectedHeader)
|
|
142
|
+
.setUnprotectedHeader(recipient.unprotectedHeader)
|
|
143
|
+
.encrypt(recipient.key, {
|
|
144
|
+
...recipient.options,
|
|
145
|
+
...options,
|
|
146
|
+
[unprotected]: true,
|
|
147
|
+
});
|
|
148
|
+
jwe.ciphertext = flattened.ciphertext;
|
|
149
|
+
jwe.iv = flattened.iv;
|
|
150
|
+
jwe.tag = flattened.tag;
|
|
151
|
+
if (flattened.aad)
|
|
152
|
+
jwe.aad = flattened.aad;
|
|
153
|
+
if (flattened.protected)
|
|
154
|
+
jwe.protected = flattened.protected;
|
|
155
|
+
if (flattened.unprotected)
|
|
156
|
+
jwe.unprotected = flattened.unprotected;
|
|
157
|
+
target.encrypted_key = flattened.encrypted_key;
|
|
158
|
+
if (flattened.header)
|
|
159
|
+
target.header = flattened.header;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const { encryptedKey, parameters } = await encryptKeyManagement(((_a = recipient.unprotectedHeader) === null || _a === void 0 ? void 0 : _a.alg) ||
|
|
163
|
+
((_b = this._protectedHeader) === null || _b === void 0 ? void 0 : _b.alg) ||
|
|
164
|
+
((_c = this._unprotectedHeader) === null || _c === void 0 ? void 0 : _c.alg), enc, recipient.key, cek);
|
|
165
|
+
target.encrypted_key = base64url(encryptedKey);
|
|
166
|
+
if (recipient.unprotectedHeader || parameters)
|
|
167
|
+
target.header = { ...recipient.unprotectedHeader, ...parameters };
|
|
168
|
+
}
|
|
169
|
+
return jwe;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -37,17 +37,21 @@ class RemoteJWKSet {
|
|
|
37
37
|
}
|
|
38
38
|
return Date.now() < this._cooldownStarted + this._cooldownDuration;
|
|
39
39
|
}
|
|
40
|
-
async getKey(protectedHeader) {
|
|
40
|
+
async getKey(protectedHeader, token) {
|
|
41
|
+
const joseHeader = {
|
|
42
|
+
...protectedHeader,
|
|
43
|
+
...token.header,
|
|
44
|
+
};
|
|
41
45
|
if (!this._jwks) {
|
|
42
46
|
await this.reload();
|
|
43
47
|
}
|
|
44
48
|
const candidates = this._jwks.keys.filter((jwk) => {
|
|
45
|
-
let candidate = jwk.kty === getKtyFromAlg(
|
|
46
|
-
if (candidate && typeof
|
|
47
|
-
candidate =
|
|
49
|
+
let candidate = jwk.kty === getKtyFromAlg(joseHeader.alg);
|
|
50
|
+
if (candidate && typeof joseHeader.kid === 'string') {
|
|
51
|
+
candidate = joseHeader.kid === jwk.kid;
|
|
48
52
|
}
|
|
49
53
|
if (candidate && typeof jwk.alg === 'string') {
|
|
50
|
-
candidate =
|
|
54
|
+
candidate = joseHeader.alg === jwk.alg;
|
|
51
55
|
}
|
|
52
56
|
if (candidate && typeof jwk.use === 'string') {
|
|
53
57
|
candidate = jwk.use === 'sig';
|
|
@@ -55,11 +59,11 @@ class RemoteJWKSet {
|
|
|
55
59
|
if (candidate && Array.isArray(jwk.key_ops)) {
|
|
56
60
|
candidate = jwk.key_ops.includes('verify');
|
|
57
61
|
}
|
|
58
|
-
if (candidate &&
|
|
62
|
+
if (candidate && joseHeader.alg === 'EdDSA') {
|
|
59
63
|
candidate = jwk.crv === 'Ed25519' || jwk.crv === 'Ed448';
|
|
60
64
|
}
|
|
61
65
|
if (candidate) {
|
|
62
|
-
switch (
|
|
66
|
+
switch (joseHeader.alg) {
|
|
63
67
|
case 'ES256':
|
|
64
68
|
candidate = jwk.crv === 'P-256';
|
|
65
69
|
break;
|
|
@@ -81,7 +85,7 @@ class RemoteJWKSet {
|
|
|
81
85
|
if (length === 0) {
|
|
82
86
|
if (this.coolingDown() === false) {
|
|
83
87
|
await this.reload();
|
|
84
|
-
return this.getKey(protectedHeader);
|
|
88
|
+
return this.getKey(protectedHeader, token);
|
|
85
89
|
}
|
|
86
90
|
throw new JWKSNoMatchingKey();
|
|
87
91
|
}
|
|
@@ -89,14 +93,14 @@ class RemoteJWKSet {
|
|
|
89
93
|
throw new JWKSMultipleMatchingKeys();
|
|
90
94
|
}
|
|
91
95
|
const cached = this._cached.get(jwk) || this._cached.set(jwk, {}).get(jwk);
|
|
92
|
-
if (cached[
|
|
93
|
-
const keyObject = await importJWK({ ...jwk, ext: true },
|
|
96
|
+
if (cached[joseHeader.alg] === undefined) {
|
|
97
|
+
const keyObject = await importJWK({ ...jwk, ext: true }, joseHeader.alg);
|
|
94
98
|
if (keyObject instanceof Uint8Array || keyObject.type !== 'public') {
|
|
95
99
|
throw new JWKSInvalid('JSON Web Key Set members must be public keys');
|
|
96
100
|
}
|
|
97
|
-
cached[
|
|
101
|
+
cached[joseHeader.alg] = keyObject;
|
|
98
102
|
}
|
|
99
|
-
return cached[
|
|
103
|
+
return cached[joseHeader.alg];
|
|
100
104
|
}
|
|
101
105
|
async reload() {
|
|
102
106
|
if (!this._pendingFetch) {
|
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
import { FlattenedSign } from '../flattened/sign.js';
|
|
2
2
|
import { JWSInvalid } from '../../util/errors.js';
|
|
3
|
-
const signatureRef = new WeakMap();
|
|
4
3
|
class IndividualSignature {
|
|
4
|
+
constructor(sig, key, options) {
|
|
5
|
+
this.parent = sig;
|
|
6
|
+
this.key = key;
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
5
9
|
setProtectedHeader(protectedHeader) {
|
|
6
|
-
if (this.
|
|
10
|
+
if (this.protectedHeader) {
|
|
7
11
|
throw new TypeError('setProtectedHeader can only be called once');
|
|
8
12
|
}
|
|
9
|
-
this.
|
|
13
|
+
this.protectedHeader = protectedHeader;
|
|
10
14
|
return this;
|
|
11
15
|
}
|
|
12
16
|
setUnprotectedHeader(unprotectedHeader) {
|
|
13
|
-
if (this.
|
|
17
|
+
if (this.unprotectedHeader) {
|
|
14
18
|
throw new TypeError('setUnprotectedHeader can only be called once');
|
|
15
19
|
}
|
|
16
|
-
this.
|
|
20
|
+
this.unprotectedHeader = unprotectedHeader;
|
|
17
21
|
return this;
|
|
18
22
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
get _protectedHeader() {
|
|
23
|
-
return signatureRef.get(this).protectedHeader;
|
|
23
|
+
addSignature(...args) {
|
|
24
|
+
return this.parent.addSignature(...args);
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
sign(...args) {
|
|
27
|
+
return this.parent.sign(...args);
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
-
return
|
|
29
|
+
done() {
|
|
30
|
+
return this.parent;
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
export class GeneralSign {
|
|
@@ -35,8 +36,7 @@ export class GeneralSign {
|
|
|
35
36
|
this._payload = payload;
|
|
36
37
|
}
|
|
37
38
|
addSignature(key, options) {
|
|
38
|
-
const signature = new IndividualSignature();
|
|
39
|
-
signatureRef.set(signature, { key, options });
|
|
39
|
+
const signature = new IndividualSignature(this, key, options);
|
|
40
40
|
this._signatures.push(signature);
|
|
41
41
|
return signature;
|
|
42
42
|
}
|
|
@@ -48,23 +48,19 @@ export class GeneralSign {
|
|
|
48
48
|
signatures: [],
|
|
49
49
|
payload: '',
|
|
50
50
|
};
|
|
51
|
-
let
|
|
52
|
-
|
|
53
|
-
const { protectedHeader, unprotectedHeader, options, key } = signatureRef.get(sig);
|
|
51
|
+
for (let i = 0; i < this._signatures.length; i++) {
|
|
52
|
+
const signature = this._signatures[i];
|
|
54
53
|
const flattened = new FlattenedSign(this._payload);
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
flattened.setProtectedHeader(signature.protectedHeader);
|
|
55
|
+
flattened.setUnprotectedHeader(signature.unprotectedHeader);
|
|
56
|
+
const { payload, ...rest } = await flattened.sign(signature.key, signature.options);
|
|
57
|
+
if (i === 0) {
|
|
58
|
+
jws.payload = payload;
|
|
57
59
|
}
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
+
else if (jws.payload !== payload) {
|
|
61
|
+
throw new JWSInvalid('inconsistent use of JWS Unencoded Payload Option (RFC7797)');
|
|
60
62
|
}
|
|
61
|
-
const { payload, ...rest } = await flattened.sign(key, options);
|
|
62
|
-
payloads.add(payload);
|
|
63
|
-
jws.payload = payload;
|
|
64
63
|
jws.signatures.push(rest);
|
|
65
|
-
}));
|
|
66
|
-
if (payloads.size !== 1) {
|
|
67
|
-
throw new JWSInvalid('inconsistent use of JWS Unencoded Payload Option (RFC7797)');
|
|
68
64
|
}
|
|
69
65
|
return jws;
|
|
70
66
|
}
|
package/dist/node/esm/lib/cek.js
CHANGED
|
@@ -2,18 +2,17 @@ import { JOSENotSupported } from '../util/errors.js';
|
|
|
2
2
|
import random from '../runtime/random.js';
|
|
3
3
|
export function bitLength(alg) {
|
|
4
4
|
switch (alg) {
|
|
5
|
-
case 'A128CBC-HS256':
|
|
6
|
-
return 256;
|
|
7
|
-
case 'A192CBC-HS384':
|
|
8
|
-
return 384;
|
|
9
|
-
case 'A256CBC-HS512':
|
|
10
|
-
return 512;
|
|
11
5
|
case 'A128GCM':
|
|
12
6
|
return 128;
|
|
13
7
|
case 'A192GCM':
|
|
14
8
|
return 192;
|
|
15
9
|
case 'A256GCM':
|
|
10
|
+
case 'A128CBC-HS256':
|
|
16
11
|
return 256;
|
|
12
|
+
case 'A192CBC-HS384':
|
|
13
|
+
return 384;
|
|
14
|
+
case 'A256CBC-HS512':
|
|
15
|
+
return 512;
|
|
17
16
|
default:
|
|
18
17
|
throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`);
|
|
19
18
|
}
|
|
@@ -40,7 +40,7 @@ async function decryptKeyManagement(alg, key, encryptedKey, joseHeader) {
|
|
|
40
40
|
throw new JWEInvalid(`JOSE Header "apv" (Agreement PartyVInfo) invalid`);
|
|
41
41
|
partyVInfo = base64url(joseHeader.apv);
|
|
42
42
|
}
|
|
43
|
-
const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, parseInt(alg.substr(-5, 3), 10)
|
|
43
|
+
const sharedSecret = await ECDH.deriveKey(epk, key, alg === 'ECDH-ES' ? joseHeader.enc : alg, alg === 'ECDH-ES' ? cekLength(joseHeader.enc) : parseInt(alg.substr(-5, 3), 10), partyUInfo, partyVInfo);
|
|
44
44
|
if (alg === 'ECDH-ES')
|
|
45
45
|
return sharedSecret;
|
|
46
46
|
if (encryptedKey === undefined)
|
|
@@ -29,7 +29,7 @@ async function encryptKeyManagement(alg, enc, key, providedCek, providedParamete
|
|
|
29
29
|
let { epk: ephemeralKey } = providedParameters;
|
|
30
30
|
ephemeralKey || (ephemeralKey = await ECDH.generateEpk(key));
|
|
31
31
|
const { x, y, crv, kty } = await exportJWK(ephemeralKey);
|
|
32
|
-
const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, parseInt(alg.substr(-5, 3), 10)
|
|
32
|
+
const sharedSecret = await ECDH.deriveKey(key, ephemeralKey, alg === 'ECDH-ES' ? enc : alg, alg === 'ECDH-ES' ? cekLength(enc) : parseInt(alg.substr(-5, 3), 10), apu, apv);
|
|
33
33
|
parameters = { epk: { x, y, crv, kty } };
|
|
34
34
|
if (apu)
|
|
35
35
|
parameters.apu = base64url(apu);
|
package/dist/node/esm/lib/iv.js
CHANGED
|
@@ -2,24 +2,17 @@ import { JOSENotSupported } from '../util/errors.js';
|
|
|
2
2
|
import random from '../runtime/random.js';
|
|
3
3
|
export function bitLength(alg) {
|
|
4
4
|
switch (alg) {
|
|
5
|
-
case 'A128CBC-HS256':
|
|
6
|
-
return 128;
|
|
7
5
|
case 'A128GCM':
|
|
8
|
-
return 96;
|
|
9
6
|
case 'A128GCMKW':
|
|
10
|
-
return 96;
|
|
11
|
-
case 'A192CBC-HS384':
|
|
12
|
-
return 128;
|
|
13
7
|
case 'A192GCM':
|
|
14
|
-
return 96;
|
|
15
8
|
case 'A192GCMKW':
|
|
16
|
-
return 96;
|
|
17
|
-
case 'A256CBC-HS512':
|
|
18
|
-
return 128;
|
|
19
9
|
case 'A256GCM':
|
|
20
|
-
return 96;
|
|
21
10
|
case 'A256GCMKW':
|
|
22
11
|
return 96;
|
|
12
|
+
case 'A128CBC-HS256':
|
|
13
|
+
case 'A192CBC-HS384':
|
|
14
|
+
case 'A256CBC-HS512':
|
|
15
|
+
return 128;
|
|
23
16
|
default:
|
|
24
17
|
throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`);
|
|
25
18
|
}
|