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.
- package/dist/webapi/jwe/compact/decrypt.js +2 -2
- package/dist/webapi/jwe/flattened/encrypt.js +12 -12
- package/dist/webapi/jwe/general/decrypt.js +8 -0
- package/dist/webapi/jwe/general/encrypt.js +51 -52
- package/dist/webapi/jwks/local.js +13 -34
- package/dist/webapi/jwks/remote.js +17 -26
- package/dist/webapi/jws/compact/verify.js +2 -2
- package/dist/webapi/jws/flattened/sign.js +1 -9
- package/dist/webapi/jws/general/sign.js +12 -21
- package/dist/webapi/jws/general/verify.js +13 -11
- package/dist/webapi/jwt/decrypt.js +3 -3
- package/dist/webapi/jwt/verify.js +4 -4
- package/dist/webapi/key/export.js +3 -3
- package/dist/webapi/key/generate_key_pair.js +10 -9
- package/dist/webapi/key/generate_secret.js +2 -2
- package/dist/webapi/lib/asn1.js +32 -65
- package/dist/webapi/lib/content_encryption.js +16 -34
- package/dist/webapi/lib/crypto_key.js +6 -0
- package/dist/webapi/lib/invalid_key_input.js +0 -1
- package/dist/webapi/lib/jwe_algorithms.js +48 -84
- package/dist/webapi/lib/jwe_decrypt.js +46 -41
- package/dist/webapi/lib/jwe_encrypt.js +14 -13
- package/dist/webapi/lib/jwk_to_key.js +5 -10
- package/dist/webapi/lib/jws_algorithms.js +22 -23
- package/dist/webapi/lib/jws_sign.js +12 -6
- package/dist/webapi/lib/jws_verify.js +26 -27
- package/dist/webapi/lib/jwt_claims_set.js +60 -102
- package/dist/webapi/lib/key.js +61 -99
- package/dist/webapi/lib/key_algorithm.js +7 -13
- package/dist/webapi/lib/key_descriptor.js +1 -1
- package/dist/webapi/lib/key_management.js +74 -161
- package/dist/webapi/lib/options.js +11 -14
- package/dist/webapi/lib/signing.js +6 -16
- package/dist/webapi/lib/type_checks.js +13 -18
- package/dist/webapi/util/base64url.js +4 -3
- 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.
|
|
13
|
-
|
|
11
|
+
const entry = keyAlgorithm(alg, algArgument);
|
|
12
|
+
if (entry.secret) {
|
|
13
|
+
unsupportedAlg(algArgument);
|
|
14
14
|
}
|
|
15
15
|
let algorithm;
|
|
16
|
-
if (entry.
|
|
17
|
-
|
|
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:
|
|
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
|
|
45
|
-
...entry.usages
|
|
45
|
+
...entry.usages[1],
|
|
46
|
+
...entry.usages[0],
|
|
46
47
|
]);
|
|
47
48
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
37
|
+
unsupportedAlg(algArgument);
|
|
38
38
|
}
|
|
39
39
|
return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, keyUsages);
|
|
40
40
|
}
|
package/dist/webapi/lib/asn1.js
CHANGED
|
@@ -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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
|
88
|
-
expectTag(state, 0x30,
|
|
84
|
+
function parseKeyHeader(state, keyFormat) {
|
|
85
|
+
expectTag(state, 0x30, `Invalid ${keyFormat === 'spki' ? 'SPKI' : 'PKCS#8'} structure`);
|
|
89
86
|
parseLength(state);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
])
|
|
122
|
-
|
|
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.
|
|
131
|
-
|
|
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.
|
|
121
|
+
if (entry.resolve) {
|
|
136
122
|
try {
|
|
137
|
-
|
|
123
|
+
const state = createASN1State(keyData);
|
|
124
|
+
parseKeyHeader(state, keyFormat);
|
|
125
|
+
algorithm = entry.resolve({ crv: parseECAlgorithmIdentifier(state) });
|
|
138
126
|
}
|
|
139
|
-
catch
|
|
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 ??
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
54
|
-
|
|
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
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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,25 +1,24 @@
|
|
|
1
1
|
import { JOSENotSupported } from '../util/errors.js';
|
|
2
2
|
import { table } from './key_descriptor.js';
|
|
3
|
-
const wrap =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const derive =
|
|
8
|
-
const none =
|
|
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
|
-
|
|
15
|
-
keyOps: { encrypt: 'wrapKey', decrypt: 'unwrapKey' },
|
|
14
|
+
ops: ['wrapKey', 'unwrapKey'],
|
|
16
15
|
};
|
|
17
16
|
}
|
|
18
|
-
function ecdh(
|
|
17
|
+
function ecdh() {
|
|
19
18
|
return {
|
|
20
19
|
kty: ['EC', 'OKP'],
|
|
21
20
|
subtle: { name: 'ECDH' },
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
40
|
+
ops: gcm ? ['encrypt', 'decrypt'] : ['wrapKey', 'unwrapKey'],
|
|
43
41
|
};
|
|
44
42
|
}
|
|
45
|
-
function
|
|
43
|
+
function pbes2() {
|
|
46
44
|
return {
|
|
47
45
|
kty: ['oct'],
|
|
48
|
-
|
|
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
|
-
|
|
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
|
-
|
|
55
|
+
secret: true,
|
|
70
56
|
subtle: { name: 'AES-GCM' },
|
|
71
57
|
usages: none,
|
|
72
|
-
|
|
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(
|
|
80
|
-
'ECDH-ES+A192KW': ecdh(
|
|
81
|
-
'ECDH-ES+A256KW': ecdh(
|
|
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:
|
|
86
|
-
A192GCMKW:
|
|
87
|
-
A256GCMKW:
|
|
88
|
-
'PBES2-HS256+A128KW': pbes2(
|
|
89
|
-
'PBES2-HS384+A192KW': pbes2(
|
|
90
|
-
'PBES2-HS512+A256KW': pbes2(
|
|
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
|
|
93
|
-
|
|
94
|
-
function gcm(bits) {
|
|
78
|
+
const contentOps = ['encrypt', 'decrypt'];
|
|
79
|
+
function contentEncryption(bits, cbc = false) {
|
|
95
80
|
return {
|
|
96
81
|
kty: ['oct'],
|
|
97
|
-
|
|
98
|
-
subtle: { name: 'AES-GCM', length: bits },
|
|
99
|
-
usages:
|
|
100
|
-
|
|
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
|
|
87
|
+
ivBits: cbc ? 128 : 96,
|
|
88
|
+
cbc,
|
|
116
89
|
};
|
|
117
90
|
}
|
|
118
91
|
const ENC = table({
|
|
119
|
-
A128GCM:
|
|
120
|
-
A192GCM:
|
|
121
|
-
A256GCM:
|
|
122
|
-
'A128CBC-HS256':
|
|
123
|
-
'A192CBC-HS384':
|
|
124
|
-
'A256CBC-HS512':
|
|
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
|
-
|
|
127
|
-
|
|
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
|
|
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
|
-
|
|
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
|
}
|