jose 4.0.0 → 4.0.4
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/lib/cek.js +18 -16
- package/dist/browser/lib/check_iv_length.js +2 -2
- package/dist/browser/lib/crypto_key.js +160 -0
- package/dist/browser/lib/decrypt_key_management.js +2 -2
- package/dist/browser/lib/encrypt_key_management.js +2 -2
- package/dist/browser/lib/iv.js +24 -19
- package/dist/browser/runtime/aeskw.js +5 -3
- package/dist/browser/runtime/check_cek_length.js +4 -34
- package/dist/browser/runtime/decrypt.js +18 -6
- package/dist/browser/runtime/ecdhes.js +3 -0
- package/dist/browser/runtime/encrypt.js +18 -6
- package/dist/browser/runtime/get_sign_verify_key.js +2 -0
- package/dist/browser/runtime/pbes2kw.js +5 -3
- package/dist/browser/runtime/rsaes.js +3 -0
- package/dist/node/cjs/lib/cek.js +20 -17
- package/dist/node/cjs/lib/check_iv_length.js +1 -1
- package/dist/node/cjs/lib/crypto_key.js +165 -0
- 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 +26 -20
- package/dist/node/cjs/runtime/aeskw.js +3 -1
- package/dist/node/cjs/runtime/asn1.js +1 -1
- package/dist/node/cjs/runtime/decrypt.js +3 -1
- package/dist/node/cjs/runtime/ecdhes.js +6 -3
- package/dist/node/cjs/runtime/encrypt.js +3 -1
- package/dist/node/cjs/runtime/fetch_jwks.js +13 -9
- package/dist/node/cjs/runtime/get_named_curve.js +1 -1
- package/dist/node/cjs/runtime/get_sign_verify_key.js +5 -3
- package/dist/node/cjs/runtime/global.js +11 -0
- package/dist/node/cjs/runtime/key_to_jwk.js +1 -1
- package/dist/node/cjs/runtime/pbes2kw.js +3 -1
- package/dist/node/cjs/runtime/rsaes.js +3 -1
- package/dist/node/cjs/runtime/webcrypto.js +1 -149
- package/dist/node/esm/lib/cek.js +18 -16
- package/dist/node/esm/lib/check_iv_length.js +2 -2
- package/dist/node/esm/lib/crypto_key.js +160 -0
- package/dist/node/esm/lib/decrypt_key_management.js +2 -2
- package/dist/node/esm/lib/encrypt_key_management.js +2 -2
- package/dist/node/esm/lib/iv.js +24 -19
- package/dist/node/esm/runtime/aeskw.js +5 -3
- package/dist/node/esm/runtime/asn1.js +3 -3
- package/dist/node/esm/runtime/decrypt.js +5 -3
- package/dist/node/esm/runtime/ecdhes.js +8 -5
- package/dist/node/esm/runtime/encrypt.js +5 -3
- package/dist/node/esm/runtime/fetch_jwks.js +13 -9
- package/dist/node/esm/runtime/get_named_curve.js +3 -3
- package/dist/node/esm/runtime/get_sign_verify_key.js +6 -4
- package/dist/node/esm/runtime/global.js +6 -0
- package/dist/node/esm/runtime/key_to_jwk.js +3 -3
- package/dist/node/esm/runtime/pbes2kw.js +5 -3
- package/dist/node/esm/runtime/rsaes.js +5 -3
- package/dist/node/esm/runtime/webcrypto.js +0 -147
- package/dist/types/index.d.ts +17 -0
- package/package.json +1 -1
package/dist/browser/lib/cek.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { JOSENotSupported } from '../util/errors.js';
|
|
2
2
|
import random from '../runtime/random.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
export function bitLength(alg) {
|
|
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
|
+
case 'A128GCM':
|
|
12
|
+
return 128;
|
|
13
|
+
case 'A192GCM':
|
|
14
|
+
return 192;
|
|
15
|
+
case 'A256GCM':
|
|
16
|
+
return 256;
|
|
17
|
+
default:
|
|
18
|
+
throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`);
|
|
15
19
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export default generateCek;
|
|
19
|
-
export { bitLengths };
|
|
20
|
+
}
|
|
21
|
+
export default (alg) => random(new Uint8Array(bitLength(alg) >> 3));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { JWEInvalid } from '../util/errors.js';
|
|
2
|
-
import {
|
|
2
|
+
import { bitLength } from './iv.js';
|
|
3
3
|
const checkIvLength = (enc, iv) => {
|
|
4
|
-
if (iv.length << 3 !==
|
|
4
|
+
if (iv.length << 3 !== bitLength(enc)) {
|
|
5
5
|
throw new JWEInvalid('Invalid Initialization Vector length');
|
|
6
6
|
}
|
|
7
7
|
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { isCloudflareWorkers, isNodeJs } from '../runtime/global.js';
|
|
2
|
+
function getHashLength(hash) {
|
|
3
|
+
return parseInt(hash === null || hash === void 0 ? void 0 : hash.name.substr(4), 10);
|
|
4
|
+
}
|
|
5
|
+
function getNamedCurve(alg) {
|
|
6
|
+
switch (alg) {
|
|
7
|
+
case 'ES256':
|
|
8
|
+
return 'P-256';
|
|
9
|
+
case 'ES384':
|
|
10
|
+
return 'P-384';
|
|
11
|
+
case 'ES512':
|
|
12
|
+
return 'P-521';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function checkUsage(key, usages) {
|
|
16
|
+
if (usages.length && !usages.some((expected) => key.usages.includes(expected))) {
|
|
17
|
+
let msg = 'CryptoKey does not support this operation, its usages must include ';
|
|
18
|
+
if (usages.length > 2) {
|
|
19
|
+
const last = usages.pop();
|
|
20
|
+
msg += `one of ${usages.join(', ')}, or ${last}.`;
|
|
21
|
+
}
|
|
22
|
+
else if (usages.length === 2) {
|
|
23
|
+
msg += `one of ${usages[0]} or ${usages[1]}.`;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
msg += `${usages[0]}.`;
|
|
27
|
+
}
|
|
28
|
+
throw new TypeError(msg);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function checkSigCryptoKey(key, alg, ...usages) {
|
|
32
|
+
switch (alg) {
|
|
33
|
+
case 'HS256':
|
|
34
|
+
case 'HS384':
|
|
35
|
+
case 'HS512': {
|
|
36
|
+
if (key.algorithm.name !== 'HMAC') {
|
|
37
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be HMAC.`);
|
|
38
|
+
}
|
|
39
|
+
const expected = parseInt(alg.substr(2), 10);
|
|
40
|
+
const actual = getHashLength(key.algorithm.hash);
|
|
41
|
+
if (actual !== expected) {
|
|
42
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`);
|
|
43
|
+
}
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
case 'RS256':
|
|
47
|
+
case 'RS384':
|
|
48
|
+
case 'RS512': {
|
|
49
|
+
if (key.algorithm.name !== 'RSASSA-PKCS1-v1_5') {
|
|
50
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSASSA-PKCS1-v1_5.`);
|
|
51
|
+
}
|
|
52
|
+
const expected = parseInt(alg.substr(2), 10);
|
|
53
|
+
const actual = getHashLength(key.algorithm.hash);
|
|
54
|
+
if (actual !== expected) {
|
|
55
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`);
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case 'PS256':
|
|
60
|
+
case 'PS384':
|
|
61
|
+
case 'PS512': {
|
|
62
|
+
if (key.algorithm.name !== 'RSA-PSS') {
|
|
63
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSA-PSS.`);
|
|
64
|
+
}
|
|
65
|
+
const expected = parseInt(alg.substr(2), 10);
|
|
66
|
+
const actual = getHashLength(key.algorithm.hash);
|
|
67
|
+
if (actual !== expected) {
|
|
68
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`);
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case isNodeJs() && 'EdDSA': {
|
|
73
|
+
if (key.algorithm.name !== 'NODE-ED25519' && key.algorithm.name !== 'NODE-ED448') {
|
|
74
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be NODE-ED25519 or NODE-ED448.`);
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case isCloudflareWorkers() && 'EdDSA': {
|
|
79
|
+
if (key.algorithm.name !== 'NODE-ED25519') {
|
|
80
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be NODE-ED25519.`);
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case 'ES256':
|
|
85
|
+
case 'ES384':
|
|
86
|
+
case 'ES512': {
|
|
87
|
+
if (key.algorithm.name !== 'ECDSA') {
|
|
88
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be ECDSA.`);
|
|
89
|
+
}
|
|
90
|
+
const expected = getNamedCurve(alg);
|
|
91
|
+
const actual = key.algorithm.namedCurve;
|
|
92
|
+
if (actual !== expected) {
|
|
93
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.namedCurve must be ${expected}.`);
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
default:
|
|
98
|
+
throw new TypeError('CryptoKey does not support this operation');
|
|
99
|
+
}
|
|
100
|
+
checkUsage(key, usages);
|
|
101
|
+
}
|
|
102
|
+
export function checkEncCryptoKey(key, alg, ...usages) {
|
|
103
|
+
switch (alg) {
|
|
104
|
+
case 'A128GCM':
|
|
105
|
+
case 'A192GCM':
|
|
106
|
+
case 'A256GCM': {
|
|
107
|
+
if (key.algorithm.name !== 'AES-GCM') {
|
|
108
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be AES-GCM.`);
|
|
109
|
+
}
|
|
110
|
+
const expected = parseInt(alg.substr(1, 3), 10);
|
|
111
|
+
const actual = key.algorithm.length;
|
|
112
|
+
if (actual !== expected) {
|
|
113
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.length must be ${expected}.`);
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case 'A128KW':
|
|
118
|
+
case 'A192KW':
|
|
119
|
+
case 'A256KW': {
|
|
120
|
+
if (key.algorithm.name !== 'AES-KW') {
|
|
121
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be AES-KW.`);
|
|
122
|
+
}
|
|
123
|
+
const expected = parseInt(alg.substr(1, 3), 10);
|
|
124
|
+
const actual = key.algorithm.length;
|
|
125
|
+
if (actual !== expected) {
|
|
126
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.length must be ${expected}.`);
|
|
127
|
+
}
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case 'ECDH-ES':
|
|
131
|
+
if (key.algorithm.name !== 'ECDH') {
|
|
132
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be ECDH.`);
|
|
133
|
+
}
|
|
134
|
+
break;
|
|
135
|
+
case 'PBES2-HS256+A128KW':
|
|
136
|
+
case 'PBES2-HS384+A192KW':
|
|
137
|
+
case 'PBES2-HS512+A256KW':
|
|
138
|
+
if (key.algorithm.name !== 'PBKDF2') {
|
|
139
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be PBKDF2.`);
|
|
140
|
+
}
|
|
141
|
+
break;
|
|
142
|
+
case 'RSA-OAEP':
|
|
143
|
+
case 'RSA-OAEP-256':
|
|
144
|
+
case 'RSA-OAEP-384':
|
|
145
|
+
case 'RSA-OAEP-512': {
|
|
146
|
+
if (key.algorithm.name !== 'RSA-OAEP') {
|
|
147
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.name must be RSA-OAEP.`);
|
|
148
|
+
}
|
|
149
|
+
const expected = parseInt(alg.substr(9), 10) || 1;
|
|
150
|
+
const actual = getHashLength(key.algorithm.hash);
|
|
151
|
+
if (actual !== expected) {
|
|
152
|
+
throw new TypeError(`CryptoKey does not support this operation, its algorithm.hash must be SHA-${expected}.`);
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
default:
|
|
157
|
+
throw new TypeError('CryptoKey does not support this operation');
|
|
158
|
+
}
|
|
159
|
+
checkUsage(key, usages);
|
|
160
|
+
}
|
|
@@ -5,7 +5,7 @@ import { decrypt as rsaEs } from '../runtime/rsaes.js';
|
|
|
5
5
|
import { unwrap as aesGcmKw } from '../runtime/aesgcmkw.js';
|
|
6
6
|
import { decode as base64url } from '../runtime/base64url.js';
|
|
7
7
|
import { JOSENotSupported, JWEInvalid } from '../util/errors.js';
|
|
8
|
-
import {
|
|
8
|
+
import { bitLength as cekLength } from '../lib/cek.js';
|
|
9
9
|
import { importJWK } from '../key/import.js';
|
|
10
10
|
import checkKeyType from './check_key_type.js';
|
|
11
11
|
import isObject from './is_object.js';
|
|
@@ -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, parseInt(alg.substr(-5, 3), 10) || cekLength(joseHeader.enc), partyUInfo, partyVInfo);
|
|
44
44
|
if (alg === 'ECDH-ES')
|
|
45
45
|
return sharedSecret;
|
|
46
46
|
if (encryptedKey === undefined)
|
|
@@ -4,7 +4,7 @@ import { encrypt as pbes2Kw } from '../runtime/pbes2kw.js';
|
|
|
4
4
|
import { encrypt as rsaEs } from '../runtime/rsaes.js';
|
|
5
5
|
import { wrap as aesGcmKw } from '../runtime/aesgcmkw.js';
|
|
6
6
|
import { encode as base64url } from '../runtime/base64url.js';
|
|
7
|
-
import generateCek, {
|
|
7
|
+
import generateCek, { bitLength as cekLength } from '../lib/cek.js';
|
|
8
8
|
import { JOSENotSupported } from '../util/errors.js';
|
|
9
9
|
import { exportJWK } from '../key/export.js';
|
|
10
10
|
import checkKeyType from './check_key_type.js';
|
|
@@ -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, parseInt(alg.substr(-5, 3), 10) || cekLength(enc), apu, apv);
|
|
33
33
|
parameters = { epk: { x, y, crv, kty } };
|
|
34
34
|
if (apu)
|
|
35
35
|
parameters.apu = base64url(apu);
|
package/dist/browser/lib/iv.js
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import { JOSENotSupported } from '../util/errors.js';
|
|
2
2
|
import random from '../runtime/random.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
export function bitLength(alg) {
|
|
4
|
+
switch (alg) {
|
|
5
|
+
case 'A128CBC-HS256':
|
|
6
|
+
return 128;
|
|
7
|
+
case 'A128GCM':
|
|
8
|
+
return 96;
|
|
9
|
+
case 'A128GCMKW':
|
|
10
|
+
return 96;
|
|
11
|
+
case 'A192CBC-HS384':
|
|
12
|
+
return 128;
|
|
13
|
+
case 'A192GCM':
|
|
14
|
+
return 96;
|
|
15
|
+
case 'A192GCMKW':
|
|
16
|
+
return 96;
|
|
17
|
+
case 'A256CBC-HS512':
|
|
18
|
+
return 128;
|
|
19
|
+
case 'A256GCM':
|
|
20
|
+
return 96;
|
|
21
|
+
case 'A256GCMKW':
|
|
22
|
+
return 96;
|
|
23
|
+
default:
|
|
24
|
+
throw new JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`);
|
|
18
25
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export default generateIv;
|
|
22
|
-
export { bitLengths };
|
|
26
|
+
}
|
|
27
|
+
export default (alg) => random(new Uint8Array(bitLength(alg) >> 3));
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import bogusWebCrypto from './bogus.js';
|
|
2
2
|
import crypto, { isCryptoKey } from './webcrypto.js';
|
|
3
|
+
import { checkEncCryptoKey } from '../lib/crypto_key.js';
|
|
3
4
|
import invalidKeyInput from './invalid_key_input.js';
|
|
4
5
|
function checkKeySize(key, alg) {
|
|
5
6
|
if (key.algorithm.length !== parseInt(alg.substr(1, 3), 10)) {
|
|
6
7
|
throw new TypeError(`Invalid key size for alg: ${alg}`);
|
|
7
8
|
}
|
|
8
9
|
}
|
|
9
|
-
function getCryptoKey(key, usage) {
|
|
10
|
+
function getCryptoKey(key, alg, usage) {
|
|
10
11
|
if (isCryptoKey(key)) {
|
|
12
|
+
checkEncCryptoKey(key, alg, usage);
|
|
11
13
|
return key;
|
|
12
14
|
}
|
|
13
15
|
if (key instanceof Uint8Array) {
|
|
@@ -16,13 +18,13 @@ function getCryptoKey(key, usage) {
|
|
|
16
18
|
throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array'));
|
|
17
19
|
}
|
|
18
20
|
export const wrap = async (alg, key, cek) => {
|
|
19
|
-
const cryptoKey = await getCryptoKey(key, 'wrapKey');
|
|
21
|
+
const cryptoKey = await getCryptoKey(key, alg, 'wrapKey');
|
|
20
22
|
checkKeySize(cryptoKey, alg);
|
|
21
23
|
const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, ...bogusWebCrypto);
|
|
22
24
|
return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW'));
|
|
23
25
|
};
|
|
24
26
|
export const unwrap = async (alg, key, encryptedKey) => {
|
|
25
|
-
const cryptoKey = await getCryptoKey(key, 'unwrapKey');
|
|
27
|
+
const cryptoKey = await getCryptoKey(key, alg, 'unwrapKey');
|
|
26
28
|
checkKeySize(cryptoKey, alg);
|
|
27
29
|
const cryptoKeyCek = await crypto.subtle.unwrapKey('raw', encryptedKey, cryptoKey, 'AES-KW', ...bogusWebCrypto);
|
|
28
30
|
return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek));
|
|
@@ -1,37 +1,7 @@
|
|
|
1
|
-
import { JWEInvalid
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
switch (enc) {
|
|
6
|
-
case 'A128CBC-HS256':
|
|
7
|
-
case 'A192CBC-HS384':
|
|
8
|
-
case 'A256CBC-HS512':
|
|
9
|
-
expected = parseInt(enc.substr(-3), 10);
|
|
10
|
-
if (!(cek instanceof Uint8Array)) {
|
|
11
|
-
throw new TypeError(`${enc} content encryption requires Uint8Array as key input`);
|
|
12
|
-
}
|
|
13
|
-
break;
|
|
14
|
-
case 'A128GCM':
|
|
15
|
-
case 'A192GCM':
|
|
16
|
-
case 'A256GCM':
|
|
17
|
-
expected = parseInt(enc.substr(1, 3), 10);
|
|
18
|
-
break;
|
|
19
|
-
default:
|
|
20
|
-
throw new JOSENotSupported(`Content Encryption Algorithm ${enc} is not supported either by JOSE or your javascript runtime`);
|
|
1
|
+
import { JWEInvalid } from '../util/errors.js';
|
|
2
|
+
const checkCekLength = (cek, expected) => {
|
|
3
|
+
if (cek.length << 3 !== expected) {
|
|
4
|
+
throw new JWEInvalid('Invalid Content Encryption Key length');
|
|
21
5
|
}
|
|
22
|
-
if (cek instanceof Uint8Array) {
|
|
23
|
-
if (cek.length << 3 !== expected) {
|
|
24
|
-
throw new JWEInvalid('Invalid Content Encryption Key length');
|
|
25
|
-
}
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
if (isCryptoKey(cek)) {
|
|
29
|
-
const { length } = cek.algorithm;
|
|
30
|
-
if (length !== expected) {
|
|
31
|
-
throw new JWEInvalid('Invalid Content Encryption Key length');
|
|
32
|
-
}
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
throw new TypeError('Invalid Content Encryption Key type');
|
|
36
6
|
};
|
|
37
7
|
export default checkCekLength;
|
|
@@ -4,8 +4,12 @@ import checkCekLength from './check_cek_length.js';
|
|
|
4
4
|
import timingSafeEqual from './timing_safe_equal.js';
|
|
5
5
|
import { JOSENotSupported, JWEDecryptionFailed } from '../util/errors.js';
|
|
6
6
|
import crypto, { isCryptoKey } from './webcrypto.js';
|
|
7
|
+
import { checkEncCryptoKey } from '../lib/crypto_key.js';
|
|
7
8
|
import invalidKeyInput from './invalid_key_input.js';
|
|
8
9
|
async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
10
|
+
if (!(cek instanceof Uint8Array)) {
|
|
11
|
+
throw new TypeError(invalidKeyInput(cek, 'Uint8Array'));
|
|
12
|
+
}
|
|
9
13
|
const keySize = parseInt(enc.substr(1, 3), 10);
|
|
10
14
|
const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, ['decrypt']);
|
|
11
15
|
const macKey = await crypto.subtle.importKey('raw', cek.subarray(0, keySize >> 3), {
|
|
@@ -34,10 +38,15 @@ async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
|
34
38
|
}
|
|
35
39
|
return plaintext;
|
|
36
40
|
}
|
|
37
|
-
async function gcmDecrypt(cek, ciphertext, iv, tag, aad) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
async function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) {
|
|
42
|
+
let encKey;
|
|
43
|
+
if (cek instanceof Uint8Array) {
|
|
44
|
+
encKey = await crypto.subtle.importKey('raw', cek, 'AES-GCM', false, ['decrypt']);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
checkEncCryptoKey(cek, enc, 'decrypt');
|
|
48
|
+
encKey = cek;
|
|
49
|
+
}
|
|
41
50
|
try {
|
|
42
51
|
return new Uint8Array(await crypto.subtle.decrypt({
|
|
43
52
|
additionalData: aad,
|
|
@@ -54,17 +63,20 @@ const decrypt = async (enc, cek, ciphertext, iv, tag, aad) => {
|
|
|
54
63
|
if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) {
|
|
55
64
|
throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'Uint8Array'));
|
|
56
65
|
}
|
|
57
|
-
checkCekLength(enc, cek);
|
|
58
66
|
checkIvLength(enc, iv);
|
|
59
67
|
switch (enc) {
|
|
60
68
|
case 'A128CBC-HS256':
|
|
61
69
|
case 'A192CBC-HS384':
|
|
62
70
|
case 'A256CBC-HS512':
|
|
71
|
+
if (cek instanceof Uint8Array)
|
|
72
|
+
checkCekLength(cek, parseInt(enc.substr(-3), 10));
|
|
63
73
|
return cbcDecrypt(enc, cek, ciphertext, iv, tag, aad);
|
|
64
74
|
case 'A128GCM':
|
|
65
75
|
case 'A192GCM':
|
|
66
76
|
case 'A256GCM':
|
|
67
|
-
|
|
77
|
+
if (cek instanceof Uint8Array)
|
|
78
|
+
checkCekLength(cek, parseInt(enc.substr(1, 3), 10));
|
|
79
|
+
return gcmDecrypt(enc, cek, ciphertext, iv, tag, aad);
|
|
68
80
|
default:
|
|
69
81
|
throw new JOSENotSupported('Unsupported JWE Content Encryption Algorithm');
|
|
70
82
|
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { encoder, concat, uint32be, lengthAndInput, concatKdf } from '../lib/buffer_utils.js';
|
|
2
2
|
import crypto, { isCryptoKey } from './webcrypto.js';
|
|
3
|
+
import { checkEncCryptoKey } from '../lib/crypto_key.js';
|
|
3
4
|
import digest from './digest.js';
|
|
4
5
|
import invalidKeyInput from './invalid_key_input.js';
|
|
5
6
|
export const deriveKey = async (publicKey, privateKey, algorithm, keyLength, apu = new Uint8Array(0), apv = new Uint8Array(0)) => {
|
|
6
7
|
if (!isCryptoKey(publicKey)) {
|
|
7
8
|
throw new TypeError(invalidKeyInput(publicKey, 'CryptoKey'));
|
|
8
9
|
}
|
|
10
|
+
checkEncCryptoKey(publicKey, 'ECDH-ES');
|
|
9
11
|
if (!isCryptoKey(privateKey)) {
|
|
10
12
|
throw new TypeError(invalidKeyInput(privateKey, 'CryptoKey'));
|
|
11
13
|
}
|
|
14
|
+
checkEncCryptoKey(privateKey, 'ECDH-ES', 'deriveBits', 'deriveKey');
|
|
12
15
|
const value = concat(lengthAndInput(encoder.encode(algorithm)), lengthAndInput(apu), lengthAndInput(apv), uint32be(keyLength));
|
|
13
16
|
if (!privateKey.usages.includes('deriveBits')) {
|
|
14
17
|
throw new TypeError('ECDH-ES private key "usages" must include "deriveBits"');
|
|
@@ -2,9 +2,13 @@ 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 crypto, { isCryptoKey } from './webcrypto.js';
|
|
5
|
+
import { checkEncCryptoKey } from '../lib/crypto_key.js';
|
|
5
6
|
import invalidKeyInput from './invalid_key_input.js';
|
|
6
7
|
import { JOSENotSupported } from '../util/errors.js';
|
|
7
8
|
async function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
9
|
+
if (!(cek instanceof Uint8Array)) {
|
|
10
|
+
throw new TypeError(invalidKeyInput(cek, 'Uint8Array'));
|
|
11
|
+
}
|
|
8
12
|
const keySize = parseInt(enc.substr(1, 3), 10);
|
|
9
13
|
const encKey = await crypto.subtle.importKey('raw', cek.subarray(keySize >> 3), 'AES-CBC', false, ['encrypt']);
|
|
10
14
|
const macKey = await crypto.subtle.importKey('raw', cek.subarray(0, keySize >> 3), {
|
|
@@ -19,10 +23,15 @@ async function cbcEncrypt(enc, plaintext, cek, iv, aad) {
|
|
|
19
23
|
const tag = new Uint8Array((await crypto.subtle.sign('HMAC', macKey, macData)).slice(0, keySize >> 3));
|
|
20
24
|
return { ciphertext, tag };
|
|
21
25
|
}
|
|
22
|
-
async function gcmEncrypt(plaintext, cek, iv, aad) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
async function gcmEncrypt(enc, plaintext, cek, iv, aad) {
|
|
27
|
+
let encKey;
|
|
28
|
+
if (cek instanceof Uint8Array) {
|
|
29
|
+
encKey = await crypto.subtle.importKey('raw', cek, 'AES-GCM', false, ['encrypt']);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
checkEncCryptoKey(cek, enc, 'encrypt');
|
|
33
|
+
encKey = cek;
|
|
34
|
+
}
|
|
26
35
|
const encrypted = new Uint8Array(await crypto.subtle.encrypt({
|
|
27
36
|
additionalData: aad,
|
|
28
37
|
iv,
|
|
@@ -37,17 +46,20 @@ const encrypt = async (enc, plaintext, cek, iv, aad) => {
|
|
|
37
46
|
if (!isCryptoKey(cek) && !(cek instanceof Uint8Array)) {
|
|
38
47
|
throw new TypeError(invalidKeyInput(cek, 'CryptoKey', 'Uint8Array'));
|
|
39
48
|
}
|
|
40
|
-
checkCekLength(enc, cek);
|
|
41
49
|
checkIvLength(enc, iv);
|
|
42
50
|
switch (enc) {
|
|
43
51
|
case 'A128CBC-HS256':
|
|
44
52
|
case 'A192CBC-HS384':
|
|
45
53
|
case 'A256CBC-HS512':
|
|
54
|
+
if (cek instanceof Uint8Array)
|
|
55
|
+
checkCekLength(cek, parseInt(enc.substr(-3), 10));
|
|
46
56
|
return cbcEncrypt(enc, plaintext, cek, iv, aad);
|
|
47
57
|
case 'A128GCM':
|
|
48
58
|
case 'A192GCM':
|
|
49
59
|
case 'A256GCM':
|
|
50
|
-
|
|
60
|
+
if (cek instanceof Uint8Array)
|
|
61
|
+
checkCekLength(cek, parseInt(enc.substr(1, 3), 10));
|
|
62
|
+
return gcmEncrypt(enc, plaintext, cek, iv, aad);
|
|
51
63
|
default:
|
|
52
64
|
throw new JOSENotSupported('Unsupported JWE Content Encryption Algorithm');
|
|
53
65
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import crypto, { isCryptoKey } from './webcrypto.js';
|
|
2
|
+
import { checkSigCryptoKey } from '../lib/crypto_key.js';
|
|
2
3
|
import invalidKeyInput from './invalid_key_input.js';
|
|
3
4
|
export default function getCryptoKey(alg, key, usage) {
|
|
4
5
|
if (isCryptoKey(key)) {
|
|
6
|
+
checkSigCryptoKey(key, alg, usage);
|
|
5
7
|
return key;
|
|
6
8
|
}
|
|
7
9
|
if (key instanceof Uint8Array) {
|
|
@@ -4,12 +4,14 @@ import { encode as base64url } from './base64url.js';
|
|
|
4
4
|
import { wrap, unwrap } from './aeskw.js';
|
|
5
5
|
import checkP2s from '../lib/check_p2s.js';
|
|
6
6
|
import crypto, { isCryptoKey } from './webcrypto.js';
|
|
7
|
+
import { checkEncCryptoKey } from '../lib/crypto_key.js';
|
|
7
8
|
import invalidKeyInput from './invalid_key_input.js';
|
|
8
|
-
function getCryptoKey(key) {
|
|
9
|
+
function getCryptoKey(key, alg) {
|
|
9
10
|
if (key instanceof Uint8Array) {
|
|
10
11
|
return crypto.subtle.importKey('raw', key, 'PBKDF2', false, ['deriveBits']);
|
|
11
12
|
}
|
|
12
13
|
if (isCryptoKey(key)) {
|
|
14
|
+
checkEncCryptoKey(key, alg, 'deriveBits', 'deriveKey');
|
|
13
15
|
return key;
|
|
14
16
|
}
|
|
15
17
|
throw new TypeError(invalidKeyInput(key, 'CryptoKey', 'Uint8Array'));
|
|
@@ -28,7 +30,7 @@ export const encrypt = async (alg, key, cek, p2c = Math.floor(Math.random() * 20
|
|
|
28
30
|
length: keylen,
|
|
29
31
|
name: 'AES-KW',
|
|
30
32
|
};
|
|
31
|
-
const cryptoKey = await getCryptoKey(key);
|
|
33
|
+
const cryptoKey = await getCryptoKey(key, alg);
|
|
32
34
|
let derived;
|
|
33
35
|
if (cryptoKey.usages.includes('deriveBits')) {
|
|
34
36
|
derived = new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen));
|
|
@@ -56,7 +58,7 @@ export const decrypt = async (alg, key, encryptedKey, p2c, p2s) => {
|
|
|
56
58
|
length: keylen,
|
|
57
59
|
name: 'AES-KW',
|
|
58
60
|
};
|
|
59
|
-
const cryptoKey = await getCryptoKey(key);
|
|
61
|
+
const cryptoKey = await getCryptoKey(key, alg);
|
|
60
62
|
let derived;
|
|
61
63
|
if (cryptoKey.usages.includes('deriveBits')) {
|
|
62
64
|
derived = new Uint8Array(await crypto.subtle.deriveBits(subtleAlg, cryptoKey, keylen));
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import subtleAlgorithm from './subtle_rsaes.js';
|
|
2
2
|
import bogusWebCrypto from './bogus.js';
|
|
3
3
|
import crypto, { isCryptoKey } from './webcrypto.js';
|
|
4
|
+
import { checkEncCryptoKey } from '../lib/crypto_key.js';
|
|
4
5
|
import checkKeyLength from './check_key_length.js';
|
|
5
6
|
import invalidKeyInput from './invalid_key_input.js';
|
|
6
7
|
export const encrypt = async (alg, key, cek) => {
|
|
7
8
|
if (!isCryptoKey(key)) {
|
|
8
9
|
throw new TypeError(invalidKeyInput(key, 'CryptoKey'));
|
|
9
10
|
}
|
|
11
|
+
checkEncCryptoKey(key, alg, 'encrypt', 'wrapKey');
|
|
10
12
|
checkKeyLength(alg, key);
|
|
11
13
|
if (key.usages.includes('encrypt')) {
|
|
12
14
|
return new Uint8Array(await crypto.subtle.encrypt(subtleAlgorithm(alg), key, cek));
|
|
@@ -21,6 +23,7 @@ export const decrypt = async (alg, key, encryptedKey) => {
|
|
|
21
23
|
if (!isCryptoKey(key)) {
|
|
22
24
|
throw new TypeError(invalidKeyInput(key, 'CryptoKey'));
|
|
23
25
|
}
|
|
26
|
+
checkEncCryptoKey(key, alg, 'decrypt', 'unwrapKey');
|
|
24
27
|
checkKeyLength(alg, key);
|
|
25
28
|
if (key.usages.includes('decrypt')) {
|
|
26
29
|
return new Uint8Array(await crypto.subtle.decrypt(subtleAlgorithm(alg), key, encryptedKey));
|
package/dist/node/cjs/lib/cek.js
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.bitLength = void 0;
|
|
4
4
|
const errors_js_1 = require("../util/errors.js");
|
|
5
5
|
const random_js_1 = require("../runtime/random.js");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
function bitLength(alg) {
|
|
7
|
+
switch (alg) {
|
|
8
|
+
case 'A128CBC-HS256':
|
|
9
|
+
return 256;
|
|
10
|
+
case 'A192CBC-HS384':
|
|
11
|
+
return 384;
|
|
12
|
+
case 'A256CBC-HS512':
|
|
13
|
+
return 512;
|
|
14
|
+
case 'A128GCM':
|
|
15
|
+
return 128;
|
|
16
|
+
case 'A192GCM':
|
|
17
|
+
return 192;
|
|
18
|
+
case 'A256GCM':
|
|
19
|
+
return 256;
|
|
20
|
+
default:
|
|
21
|
+
throw new errors_js_1.JOSENotSupported(`Unsupported JWE Algorithm: ${alg}`);
|
|
19
22
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
exports.default =
|
|
23
|
+
}
|
|
24
|
+
exports.bitLength = bitLength;
|
|
25
|
+
exports.default = (alg) => (0, random_js_1.default)(new Uint8Array(bitLength(alg) >> 3));
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const errors_js_1 = require("../util/errors.js");
|
|
4
4
|
const iv_js_1 = require("./iv.js");
|
|
5
5
|
const checkIvLength = (enc, iv) => {
|
|
6
|
-
if (iv.length << 3 !== iv_js_1.
|
|
6
|
+
if (iv.length << 3 !== (0, iv_js_1.bitLength)(enc)) {
|
|
7
7
|
throw new errors_js_1.JWEInvalid('Invalid Initialization Vector length');
|
|
8
8
|
}
|
|
9
9
|
};
|