jose 6.2.6 → 6.2.8

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.
Files changed (36) hide show
  1. package/dist/webapi/jwe/compact/decrypt.js +2 -2
  2. package/dist/webapi/jwe/flattened/encrypt.js +12 -12
  3. package/dist/webapi/jwe/general/decrypt.js +8 -0
  4. package/dist/webapi/jwe/general/encrypt.js +51 -52
  5. package/dist/webapi/jwks/local.js +13 -34
  6. package/dist/webapi/jwks/remote.js +17 -26
  7. package/dist/webapi/jws/compact/verify.js +2 -2
  8. package/dist/webapi/jws/flattened/sign.js +1 -9
  9. package/dist/webapi/jws/general/sign.js +12 -21
  10. package/dist/webapi/jws/general/verify.js +13 -11
  11. package/dist/webapi/jwt/decrypt.js +3 -3
  12. package/dist/webapi/jwt/verify.js +4 -4
  13. package/dist/webapi/key/export.js +3 -3
  14. package/dist/webapi/key/generate_key_pair.js +10 -9
  15. package/dist/webapi/key/generate_secret.js +2 -2
  16. package/dist/webapi/lib/asn1.js +32 -65
  17. package/dist/webapi/lib/content_encryption.js +16 -34
  18. package/dist/webapi/lib/crypto_key.js +6 -0
  19. package/dist/webapi/lib/invalid_key_input.js +0 -1
  20. package/dist/webapi/lib/jwe_algorithms.js +48 -84
  21. package/dist/webapi/lib/jwe_decrypt.js +46 -41
  22. package/dist/webapi/lib/jwe_encrypt.js +14 -13
  23. package/dist/webapi/lib/jwk_to_key.js +5 -10
  24. package/dist/webapi/lib/jws_algorithms.js +22 -23
  25. package/dist/webapi/lib/jws_sign.js +12 -6
  26. package/dist/webapi/lib/jws_verify.js +26 -27
  27. package/dist/webapi/lib/jwt_claims_set.js +60 -102
  28. package/dist/webapi/lib/key.js +61 -99
  29. package/dist/webapi/lib/key_algorithm.js +7 -13
  30. package/dist/webapi/lib/key_descriptor.js +1 -1
  31. package/dist/webapi/lib/key_management.js +74 -161
  32. package/dist/webapi/lib/options.js +11 -14
  33. package/dist/webapi/lib/signing.js +6 -16
  34. package/dist/webapi/lib/type_checks.js +13 -18
  35. package/dist/webapi/util/base64url.js +4 -3
  36. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { JOSENotSupported } from '../util/errors.js';
2
- import { keyAlgorithm } from '../lib/key_algorithm.js';
2
+ import { keyAlgorithm, unsupportedAlg, algArgument } from '../lib/key_algorithm.js';
3
3
  function getModulusLengthOption(options) {
4
4
  const modulusLength = options?.modulusLength ?? 2048;
5
5
  if (typeof modulusLength !== 'number' || modulusLength < 2048) {
@@ -8,17 +8,18 @@ function getModulusLengthOption(options) {
8
8
  return modulusLength;
9
9
  }
10
10
  export async function generateKeyPair(alg, options) {
11
- const entry = keyAlgorithm(alg);
12
- if (entry.symmetric) {
13
- throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
11
+ const entry = keyAlgorithm(alg, algArgument);
12
+ if (entry.secret) {
13
+ unsupportedAlg(algArgument);
14
14
  }
15
15
  let algorithm;
16
- if (entry.subtleFor) {
17
- switch (options?.crv ?? 'P-256') {
16
+ if (entry.resolve) {
17
+ const crv = options?.crv ?? 'P-256';
18
+ switch (crv) {
18
19
  case 'P-256':
19
20
  case 'P-384':
20
21
  case 'P-521':
21
- algorithm = { name: 'ECDH', namedCurve: options?.crv ?? 'P-256' };
22
+ algorithm = { name: 'ECDH', namedCurve: crv };
22
23
  break;
23
24
  case 'X25519':
24
25
  algorithm = { name: 'X25519' };
@@ -41,7 +42,7 @@ export async function generateKeyPair(alg, options) {
41
42
  : entry.subtle;
42
43
  }
43
44
  return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, [
44
- ...entry.usages.private,
45
- ...entry.usages.public,
45
+ ...entry.usages[1],
46
+ ...entry.usages[0],
46
47
  ]);
47
48
  }
@@ -1,4 +1,4 @@
1
- import { JOSENotSupported } from '../util/errors.js';
1
+ import { unsupportedAlg, algArgument } from '../lib/key_algorithm.js';
2
2
  export async function generateSecret(alg, options) {
3
3
  let length;
4
4
  let algorithm;
@@ -34,7 +34,7 @@ export async function generateSecret(alg, options) {
34
34
  keyUsages = ['encrypt', 'decrypt'];
35
35
  break;
36
36
  default:
37
- throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
37
+ unsupportedAlg(algArgument);
38
38
  }
39
39
  return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, keyUsages);
40
40
  }
@@ -1,7 +1,7 @@
1
1
  import { invalidKeyInput } from './invalid_key_input.js';
2
2
  import { encodeBase64, decodeBase64 } from '../lib/base64.js';
3
3
  import { JOSENotSupported } from '../util/errors.js';
4
- import { keyAlgorithm } from './key_algorithm.js';
4
+ import { keyAlgorithm, unsupportedAlg, algArgument } from './key_algorithm.js';
5
5
  import { isCryptoKey, isKeyObject } from './is_key_like.js';
6
6
  const formatPEM = (b64, descriptor) => {
7
7
  const newlined = (b64.match(/.{1,64}/g) || []).join('\n');
@@ -57,13 +57,10 @@ const parseLength = (state) => {
57
57
  return first;
58
58
  };
59
59
  const skipElement = (state, count = 1) => {
60
- if (count <= 0)
61
- return;
62
- state.pos++;
63
- const length = parseLength(state);
64
- state.pos += length;
65
- if (count > 1) {
66
- skipElement(state, count - 1);
60
+ while (count-- > 0) {
61
+ state.pos++;
62
+ const length = parseLength(state);
63
+ state.pos += length;
67
64
  }
68
65
  };
69
66
  const expectTag = (state, expectedTag, errorMessage) => {
@@ -84,24 +81,16 @@ const parseAlgorithmOID = (state) => {
84
81
  const oidLen = parseLength(state);
85
82
  return getSubarray(state, oidLen);
86
83
  };
87
- function parsePKCS8Header(state) {
88
- expectTag(state, 0x30, 'Invalid PKCS#8 structure');
84
+ function parseKeyHeader(state, keyFormat) {
85
+ expectTag(state, 0x30, `Invalid ${keyFormat === 'spki' ? 'SPKI' : 'PKCS#8'} structure`);
89
86
  parseLength(state);
90
- expectTag(state, 0x02, 'Expected version field');
91
- const verLen = parseLength(state);
92
- state.pos += verLen;
87
+ if (keyFormat === 'pkcs8') {
88
+ expectTag(state, 0x02, 'Expected version field');
89
+ const length = parseLength(state);
90
+ state.pos += length;
91
+ }
93
92
  expectTag(state, 0x30, 'Expected algorithm identifier');
94
- const algIdLen = parseLength(state);
95
- const algIdStart = state.pos;
96
- return { algIdStart, algIdLength: algIdLen };
97
- }
98
- function parseSPKIHeader(state) {
99
- expectTag(state, 0x30, 'Invalid SPKI structure');
100
93
  parseLength(state);
101
- expectTag(state, 0x30, 'Expected algorithm identifier');
102
- const algIdLen = parseLength(state);
103
- const algIdStart = state.pos;
104
- return { algIdStart, algIdLength: algIdLen };
105
94
  }
106
95
  const parseECAlgorithmIdentifier = (state) => {
107
96
  const algOid = parseAlgorithmOID(state);
@@ -114,65 +103,46 @@ const parseECAlgorithmIdentifier = (state) => {
114
103
  expectTag(state, 0x06, 'Expected curve OID');
115
104
  const curveOidLen = parseLength(state);
116
105
  const curveOid = getSubarray(state, curveOidLen);
117
- for (const { name, oid } of [
118
- { name: 'P-256', oid: [0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07] },
119
- { name: 'P-384', oid: [0x2b, 0x81, 0x04, 0x00, 0x22] },
120
- { name: 'P-521', oid: [0x2b, 0x81, 0x04, 0x00, 0x23] },
121
- ]) {
122
- if (bytesEqual(curveOid, oid)) {
123
- return name;
124
- }
125
- }
106
+ if (bytesEqual(curveOid, [0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07]))
107
+ return 'P-256';
108
+ if (bytesEqual(curveOid, [0x2b, 0x81, 0x04, 0x00, 0x22]))
109
+ return 'P-384';
110
+ if (bytesEqual(curveOid, [0x2b, 0x81, 0x04, 0x00, 0x23]))
111
+ return 'P-521';
126
112
  throw new Error('Unsupported named curve');
127
113
  };
128
114
  const genericImport = async (keyFormat, keyData, alg, options) => {
129
- const entry = keyAlgorithm(alg);
130
- if (entry.symmetric) {
131
- throw new JOSENotSupported('Invalid or unsupported "alg" (Algorithm) value');
115
+ const entry = keyAlgorithm(alg, algArgument);
116
+ if (entry.secret) {
117
+ unsupportedAlg(algArgument);
132
118
  }
133
119
  const isPublic = keyFormat === 'spki';
134
120
  let algorithm;
135
- if (entry.subtleFor) {
121
+ if (entry.resolve) {
136
122
  try {
137
- algorithm = entry.subtleFor({ crv: options.getNamedCurve(keyData) });
123
+ const state = createASN1State(keyData);
124
+ parseKeyHeader(state, keyFormat);
125
+ algorithm = entry.resolve({ crv: parseECAlgorithmIdentifier(state) });
138
126
  }
139
- catch (cause) {
127
+ catch {
140
128
  throw new JOSENotSupported('Invalid or unsupported key format');
141
129
  }
142
130
  }
143
131
  else {
144
132
  algorithm = entry.subtle;
145
133
  }
146
- return crypto.subtle.importKey(keyFormat, keyData, algorithm, options?.extractable ?? (isPublic ? true : false), isPublic ? entry.usages.public : entry.usages.private);
134
+ return crypto.subtle.importKey(keyFormat, keyData, algorithm, options?.extractable ?? isPublic, entry.usages[isPublic ? 0 : 1]);
147
135
  };
148
136
  const processPEMData = (pem, pattern) => {
149
137
  return decodeBase64(pem.replace(pattern, ''));
150
138
  };
151
139
  export const fromPKCS8 = (pem, alg, options) => {
152
140
  const keyData = processPEMData(pem, /(?:-----(?:BEGIN|END) PRIVATE KEY-----|\s)/g);
153
- let opts = options;
154
- if (alg?.startsWith?.('ECDH-ES')) {
155
- opts ||= {};
156
- opts.getNamedCurve = (keyData) => {
157
- const state = createASN1State(keyData);
158
- parsePKCS8Header(state);
159
- return parseECAlgorithmIdentifier(state);
160
- };
161
- }
162
- return genericImport('pkcs8', keyData, alg, opts);
141
+ return genericImport('pkcs8', keyData, alg, options);
163
142
  };
164
143
  export const fromSPKI = (pem, alg, options) => {
165
144
  const keyData = processPEMData(pem, /(?:-----(?:BEGIN|END) PUBLIC KEY-----|\s)/g);
166
- let opts = options;
167
- if (alg?.startsWith?.('ECDH-ES')) {
168
- opts ||= {};
169
- opts.getNamedCurve = (keyData) => {
170
- const state = createASN1State(keyData);
171
- parseSPKIHeader(state);
172
- return parseECAlgorithmIdentifier(state);
173
- };
174
- }
175
- return genericImport('spki', keyData, alg, opts);
145
+ return genericImport('spki', keyData, alg, options);
176
146
  };
177
147
  function spkiFromX509(buf) {
178
148
  const state = createASN1State(buf);
@@ -191,17 +161,14 @@ function spkiFromX509(buf) {
191
161
  const spkiContentLen = parseLength(state);
192
162
  return buf.subarray(spkiStart, spkiStart + spkiContentLen + (state.pos - spkiStart));
193
163
  }
194
- function extractX509SPKI(x509) {
195
- const derBytes = processPEMData(x509, /(?:-----(?:BEGIN|END) CERTIFICATE-----|\s)/g);
196
- return spkiFromX509(derBytes);
197
- }
198
164
  export const fromX509 = (pem, alg, options) => {
199
165
  let spki;
200
166
  try {
201
- spki = extractX509SPKI(pem);
167
+ const certificate = processPEMData(pem, /(?:-----(?:BEGIN|END) CERTIFICATE-----|\s)/g);
168
+ spki = spkiFromX509(certificate);
202
169
  }
203
170
  catch (cause) {
204
171
  throw new TypeError('Failed to parse the X.509 certificate', { cause });
205
172
  }
206
- return fromSPKI(formatPEM(encodeBase64(spki), 'PUBLIC KEY'), alg, options);
173
+ return genericImport('spki', spki, alg, options);
207
174
  };
@@ -26,13 +26,13 @@ async function cbcKeySetup(enc, cek, usage) {
26
26
  hash: `SHA-${keySize << 1}`,
27
27
  name: 'HMAC',
28
28
  }, false, ['sign']);
29
- return { encKey, macKey, keySize };
29
+ return [encKey, macKey, keySize];
30
30
  }
31
31
  async function cbcHmacTag(macKey, macData, keySize) {
32
32
  return new Uint8Array((await crypto.subtle.sign('HMAC', macKey, macData)).slice(0, keySize >> 3));
33
33
  }
34
34
  async function cbcEncrypt(enc, plaintext, cek, iv, aad) {
35
- const { encKey, macKey, keySize } = await cbcKeySetup(enc, cek, 'encrypt');
35
+ const [encKey, macKey, keySize] = await cbcKeySetup(enc, cek, 'encrypt');
36
36
  const ciphertext = new Uint8Array(await crypto.subtle.encrypt({
37
37
  iv: iv,
38
38
  name: 'AES-CBC',
@@ -42,25 +42,13 @@ async function cbcEncrypt(enc, plaintext, cek, iv, aad) {
42
42
  return { ciphertext, tag, iv };
43
43
  }
44
44
  async function timingSafeEqual(a, b) {
45
- if (!(a instanceof Uint8Array)) {
46
- throw new TypeError('First argument must be a buffer');
47
- }
48
- if (!(b instanceof Uint8Array)) {
49
- throw new TypeError('Second argument must be a buffer');
50
- }
51
45
  const algorithm = { name: 'HMAC', hash: 'SHA-256' };
52
- const key = (await crypto.subtle.generateKey(algorithm, false, ['sign']));
53
- const aHmac = new Uint8Array(await crypto.subtle.sign(algorithm, key, a));
54
- const bHmac = new Uint8Array(await crypto.subtle.sign(algorithm, key, b));
55
- let out = 0;
56
- let i = -1;
57
- while (++i < 32) {
58
- out |= aHmac[i] ^ bHmac[i];
59
- }
60
- return out === 0;
46
+ const key = (await crypto.subtle.generateKey(algorithm, false, ['sign', 'verify']));
47
+ const aHmac = await crypto.subtle.sign(algorithm, key, a);
48
+ return crypto.subtle.verify(algorithm, key, aHmac, b);
61
49
  }
62
50
  async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
63
- const { encKey, macKey, keySize } = await cbcKeySetup(enc, cek, 'decrypt');
51
+ const [encKey, macKey, keySize] = await cbcKeySetup(enc, cek, 'decrypt');
64
52
  const macData = concat(aad, iv, ciphertext, uint64be(aad.length * 8));
65
53
  const expectedTag = await cbcHmacTag(macKey, macData, keySize);
66
54
  let macCheckPassed;
@@ -84,14 +72,11 @@ async function cbcDecrypt(enc, cek, ciphertext, iv, tag, aad) {
84
72
  return plaintext;
85
73
  }
86
74
  async function gcmEncrypt(enc, plaintext, cek, iv, aad) {
87
- let encKey;
88
- if (cek instanceof Uint8Array) {
89
- encKey = await crypto.subtle.importKey('raw', cek, 'AES-GCM', false, ['encrypt']);
90
- }
91
- else {
92
- checkCryptoKey(cek, enc.subtle, 'encrypt');
93
- encKey = cek;
94
- }
75
+ const encKey = cek instanceof Uint8Array
76
+ ? await crypto.subtle.importKey('raw', cek, 'AES-GCM', false, [
77
+ 'encrypt',
78
+ ])
79
+ : (checkCryptoKey(cek, enc.subtle, 'encrypt'), cek);
95
80
  const encrypted = new Uint8Array(await crypto.subtle.encrypt({
96
81
  additionalData: aad,
97
82
  iv: iv,
@@ -103,14 +88,11 @@ async function gcmEncrypt(enc, plaintext, cek, iv, aad) {
103
88
  return { ciphertext, tag, iv };
104
89
  }
105
90
  async function gcmDecrypt(enc, cek, ciphertext, iv, tag, aad) {
106
- let encKey;
107
- if (cek instanceof Uint8Array) {
108
- encKey = await crypto.subtle.importKey('raw', cek, 'AES-GCM', false, ['decrypt']);
109
- }
110
- else {
111
- checkCryptoKey(cek, enc.subtle, 'decrypt');
112
- encKey = cek;
113
- }
91
+ const encKey = cek instanceof Uint8Array
92
+ ? await crypto.subtle.importKey('raw', cek, 'AES-GCM', false, [
93
+ 'decrypt',
94
+ ])
95
+ : (checkCryptoKey(cek, enc.subtle, 'decrypt'), cek);
114
96
  try {
115
97
  return new Uint8Array(await crypto.subtle.decrypt({
116
98
  additionalData: aad,
@@ -4,6 +4,12 @@ export function checkUsage(key, usage) {
4
4
  throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
5
5
  }
6
6
  }
7
+ export function checkModulusLength(alg, key) {
8
+ const { modulusLength } = key.algorithm;
9
+ if (typeof modulusLength !== 'number' || modulusLength < 2048) {
10
+ throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
11
+ }
12
+ }
7
13
  export function checkCryptoKey(key, expected, usage) {
8
14
  const algorithm = key.algorithm;
9
15
  if (algorithm.name !== expected.name) {
@@ -1,5 +1,4 @@
1
1
  function message(msg, actual, ...types) {
2
- types = types.filter(Boolean);
3
2
  if (types.length > 2) {
4
3
  const last = types.pop();
5
4
  msg += `one of type ${types.join(', ')}, or ${last}.`;
@@ -1,25 +1,24 @@
1
1
  import { JOSENotSupported } from '../util/errors.js';
2
2
  import { table } from './key_descriptor.js';
3
- const wrap = {
4
- public: ['encrypt', 'wrapKey'],
5
- private: ['decrypt', 'unwrapKey'],
6
- };
7
- const derive = { public: [], private: ['deriveBits'] };
8
- const none = { public: [], private: [] };
3
+ const wrap = [
4
+ ['encrypt', 'wrapKey'],
5
+ ['decrypt', 'unwrapKey'],
6
+ ];
7
+ const derive = [[], ['deriveBits']];
8
+ const none = [[], []];
9
9
  function rsaes(bits) {
10
10
  return {
11
11
  kty: ['RSA'],
12
12
  subtle: { name: 'RSA-OAEP', hash: `SHA-${bits}` },
13
13
  usages: wrap,
14
- minModulusLength: 2048,
15
- keyOps: { encrypt: 'wrapKey', decrypt: 'unwrapKey' },
14
+ ops: ['wrapKey', 'unwrapKey'],
16
15
  };
17
16
  }
18
- function ecdh(kwBits) {
17
+ function ecdh() {
19
18
  return {
20
19
  kty: ['EC', 'OKP'],
21
20
  subtle: { name: 'ECDH' },
22
- subtleFor: ({ kty, crv, asymmetricKeyType }) => {
21
+ resolve: ({ kty, crv, asymmetricKeyType }) => {
23
22
  if (crv === 'X25519' || asymmetricKeyType === 'x25519') {
24
23
  return { name: 'X25519' };
25
24
  }
@@ -29,115 +28,80 @@ function ecdh(kwBits) {
29
28
  return { name: 'ECDH', namedCurve: crv };
30
29
  },
31
30
  usages: derive,
32
- kwBits,
33
- keyOps: { decrypt: 'deriveBits' },
31
+ ops: [undefined, 'deriveBits'],
34
32
  };
35
33
  }
36
- function aeskw(bits) {
34
+ function aeskw(bits, gcm = false) {
37
35
  return {
38
36
  kty: ['oct'],
39
- symmetric: true,
40
- subtle: { name: 'AES-KW', length: bits },
37
+ secret: true,
38
+ subtle: { name: gcm ? 'AES-GCM' : 'AES-KW', length: bits },
41
39
  usages: none,
42
- keyOps: { encrypt: 'wrapKey', decrypt: 'unwrapKey' },
40
+ ops: gcm ? ['encrypt', 'decrypt'] : ['wrapKey', 'unwrapKey'],
43
41
  };
44
42
  }
45
- function aesgcmkw(bits) {
43
+ function pbes2() {
46
44
  return {
47
45
  kty: ['oct'],
48
- symmetric: true,
49
- subtle: { name: 'AES-GCM', length: bits },
50
- usages: none,
51
- gcmkw: `A${bits}GCM`,
52
- keyOps: { encrypt: 'encrypt', decrypt: 'decrypt' },
53
- };
54
- }
55
- function pbes2(bits, kwBits) {
56
- return {
57
- kty: ['oct'],
58
- symmetric: true,
46
+ secret: true,
59
47
  subtle: { name: 'PBKDF2' },
60
48
  usages: none,
61
- pbes2Hash: `SHA-${bits}`,
62
- kwBits,
63
- keyOps: { encrypt: 'deriveBits', decrypt: 'deriveBits' },
49
+ ops: ['deriveBits', 'deriveBits'],
64
50
  };
65
51
  }
66
- const JWE = table({
52
+ export const JWE = table({
67
53
  dir: {
68
54
  kty: ['oct'],
69
- symmetric: true,
55
+ secret: true,
70
56
  subtle: { name: 'AES-GCM' },
71
57
  usages: none,
72
- keyOps: { encrypt: 'encrypt', decrypt: 'decrypt' },
58
+ ops: ['encrypt', 'decrypt'],
73
59
  },
74
60
  'RSA-OAEP': rsaes(1),
75
61
  'RSA-OAEP-256': rsaes(256),
76
62
  'RSA-OAEP-384': rsaes(384),
77
63
  'RSA-OAEP-512': rsaes(512),
78
64
  'ECDH-ES': ecdh(),
79
- 'ECDH-ES+A128KW': ecdh(128),
80
- 'ECDH-ES+A192KW': ecdh(192),
81
- 'ECDH-ES+A256KW': ecdh(256),
65
+ 'ECDH-ES+A128KW': ecdh(),
66
+ 'ECDH-ES+A192KW': ecdh(),
67
+ 'ECDH-ES+A256KW': ecdh(),
82
68
  A128KW: aeskw(128),
83
69
  A192KW: aeskw(192),
84
70
  A256KW: aeskw(256),
85
- A128GCMKW: aesgcmkw(128),
86
- A192GCMKW: aesgcmkw(192),
87
- A256GCMKW: aesgcmkw(256),
88
- 'PBES2-HS256+A128KW': pbes2(256, 128),
89
- 'PBES2-HS384+A192KW': pbes2(384, 192),
90
- 'PBES2-HS512+A256KW': pbes2(512, 256),
71
+ A128GCMKW: aeskw(128, true),
72
+ A192GCMKW: aeskw(192, true),
73
+ A256GCMKW: aeskw(256, true),
74
+ 'PBES2-HS256+A128KW': pbes2(),
75
+ 'PBES2-HS384+A192KW': pbes2(),
76
+ 'PBES2-HS512+A256KW': pbes2(),
91
77
  });
92
- const content = { public: [], private: [] };
93
- const contentOps = { encrypt: 'encrypt', decrypt: 'decrypt' };
94
- function gcm(bits) {
78
+ const contentOps = ['encrypt', 'decrypt'];
79
+ function contentEncryption(bits, cbc = false) {
95
80
  return {
96
81
  kty: ['oct'],
97
- symmetric: true,
98
- subtle: { name: 'AES-GCM', length: bits },
99
- usages: content,
100
- keyOps: contentOps,
101
- cekBits: bits,
102
- ivBits: 96,
103
- cbc: false,
104
- };
105
- }
106
- function cbc(bits) {
107
- return {
108
- kty: ['oct'],
109
- symmetric: true,
110
- subtle: { name: 'AES-CBC', length: bits },
111
- usages: content,
112
- keyOps: contentOps,
82
+ secret: true,
83
+ subtle: { name: cbc ? 'AES-CBC' : 'AES-GCM', length: bits },
84
+ usages: none,
85
+ ops: contentOps,
113
86
  cekBits: bits,
114
- ivBits: 128,
115
- cbc: true,
87
+ ivBits: cbc ? 128 : 96,
88
+ cbc,
116
89
  };
117
90
  }
118
91
  const ENC = table({
119
- A128GCM: gcm(128),
120
- A192GCM: gcm(192),
121
- A256GCM: gcm(256),
122
- 'A128CBC-HS256': cbc(256),
123
- 'A192CBC-HS384': cbc(384),
124
- 'A256CBC-HS512': cbc(512),
92
+ A128GCM: contentEncryption(128),
93
+ A192GCM: contentEncryption(192),
94
+ A256GCM: contentEncryption(256),
95
+ 'A128CBC-HS256': contentEncryption(256, true),
96
+ 'A192CBC-HS384': contentEncryption(384, true),
97
+ 'A256CBC-HS512': contentEncryption(512, true),
125
98
  });
126
- const unsupportedAlgHeader = 'Invalid or unsupported "alg" (JWE Algorithm) header value';
127
- export function jweAlgorithm(alg) {
128
- const entry = JWE[alg];
129
- if (!entry) {
130
- throw new JOSENotSupported(unsupportedAlgHeader);
131
- }
132
- return entry;
99
+ function unsupported(parameter, name) {
100
+ throw new JOSENotSupported(`Invalid or unsupported "${parameter}" (JWE ${name}) header value`);
133
101
  }
134
- export function maybeJWEAlgorithm(alg) {
135
- return JWE[alg];
102
+ export function jweAlgorithm(alg) {
103
+ return (typeof alg === 'string' ? JWE[alg] : undefined) ?? unsupported('alg', 'Algorithm');
136
104
  }
137
105
  export function jweEncryption(enc) {
138
- const entry = ENC[enc];
139
- if (!entry) {
140
- throw new JOSENotSupported(`Unsupported JWE Algorithm: ${enc}`);
141
- }
142
- return entry;
106
+ return ((typeof enc === 'string' ? ENC[enc] : undefined) ?? unsupported('enc', 'Encryption Algorithm'));
143
107
  }