@oari/jose 0.0.0

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 (88) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +150 -0
  3. package/dist/types/index.d.ts +55 -0
  4. package/dist/types/jwe/compact/decrypt.d.ts +43 -0
  5. package/dist/types/jwe/compact/encrypt.d.ts +76 -0
  6. package/dist/types/jwe/flattened/decrypt.d.ts +53 -0
  7. package/dist/types/jwe/flattened/encrypt.d.ts +95 -0
  8. package/dist/types/jwe/general/decrypt.d.ts +64 -0
  9. package/dist/types/jwe/general/encrypt.d.ts +89 -0
  10. package/dist/types/jwk/embedded.d.ts +31 -0
  11. package/dist/types/jwk/thumbprint.d.ts +60 -0
  12. package/dist/types/jwks/local.d.ts +90 -0
  13. package/dist/types/jwks/remote.d.ts +306 -0
  14. package/dist/types/jws/compact/sign.d.ts +47 -0
  15. package/dist/types/jws/compact/verify.d.ts +45 -0
  16. package/dist/types/jws/flattened/sign.d.ts +53 -0
  17. package/dist/types/jws/flattened/verify.d.ts +50 -0
  18. package/dist/types/jws/general/sign.d.ts +67 -0
  19. package/dist/types/jws/general/verify.d.ts +61 -0
  20. package/dist/types/jwt/decrypt.d.ts +51 -0
  21. package/dist/types/jwt/encrypt.d.ts +105 -0
  22. package/dist/types/jwt/sign.d.ts +140 -0
  23. package/dist/types/jwt/unsecured.d.ts +70 -0
  24. package/dist/types/jwt/verify.d.ts +124 -0
  25. package/dist/types/key/export.d.ts +59 -0
  26. package/dist/types/key/generate_key_pair.d.ts +64 -0
  27. package/dist/types/key/generate_secret.d.ts +42 -0
  28. package/dist/types/key/import.d.ts +146 -0
  29. package/dist/types/types.d.ts +869 -0
  30. package/dist/types/util/base64url.d.ts +9 -0
  31. package/dist/types/util/decode_jwt.d.ts +25 -0
  32. package/dist/types/util/decode_protected_header.d.ts +24 -0
  33. package/dist/types/util/errors.d.ts +488 -0
  34. package/dist/webapi/index.js +32 -0
  35. package/dist/webapi/jwe/compact/decrypt.js +27 -0
  36. package/dist/webapi/jwe/compact/encrypt.js +27 -0
  37. package/dist/webapi/jwe/flattened/decrypt.js +159 -0
  38. package/dist/webapi/jwe/flattened/encrypt.js +167 -0
  39. package/dist/webapi/jwe/general/decrypt.js +31 -0
  40. package/dist/webapi/jwe/general/encrypt.js +182 -0
  41. package/dist/webapi/jwk/embedded.js +17 -0
  42. package/dist/webapi/jwk/thumbprint.js +68 -0
  43. package/dist/webapi/jwks/local.js +119 -0
  44. package/dist/webapi/jwks/remote.js +179 -0
  45. package/dist/webapi/jws/compact/sign.js +18 -0
  46. package/dist/webapi/jws/compact/verify.js +21 -0
  47. package/dist/webapi/jws/flattened/sign.js +87 -0
  48. package/dist/webapi/jws/flattened/verify.js +110 -0
  49. package/dist/webapi/jws/general/sign.js +70 -0
  50. package/dist/webapi/jws/general/verify.js +24 -0
  51. package/dist/webapi/jwt/decrypt.js +23 -0
  52. package/dist/webapi/jwt/encrypt.js +101 -0
  53. package/dist/webapi/jwt/sign.js +52 -0
  54. package/dist/webapi/jwt/unsecured.js +63 -0
  55. package/dist/webapi/jwt/verify.js +15 -0
  56. package/dist/webapi/key/export.js +11 -0
  57. package/dist/webapi/key/generate_key_pair.js +97 -0
  58. package/dist/webapi/key/generate_secret.js +40 -0
  59. package/dist/webapi/key/import.js +57 -0
  60. package/dist/webapi/lib/aesgcmkw.js +15 -0
  61. package/dist/webapi/lib/aeskw.js +25 -0
  62. package/dist/webapi/lib/asn1.js +243 -0
  63. package/dist/webapi/lib/base64.js +22 -0
  64. package/dist/webapi/lib/buffer_utils.js +43 -0
  65. package/dist/webapi/lib/check_key_type.js +127 -0
  66. package/dist/webapi/lib/content_encryption.js +217 -0
  67. package/dist/webapi/lib/crypto_key.js +136 -0
  68. package/dist/webapi/lib/deflate.js +44 -0
  69. package/dist/webapi/lib/ecdhes.js +52 -0
  70. package/dist/webapi/lib/helpers.js +19 -0
  71. package/dist/webapi/lib/invalid_key_input.js +27 -0
  72. package/dist/webapi/lib/is_key_like.js +17 -0
  73. package/dist/webapi/lib/jwk_to_key.js +107 -0
  74. package/dist/webapi/lib/jwt_claims_set.js +238 -0
  75. package/dist/webapi/lib/key_management.js +186 -0
  76. package/dist/webapi/lib/key_to_jwk.js +31 -0
  77. package/dist/webapi/lib/normalize_key.js +166 -0
  78. package/dist/webapi/lib/pbes2kw.js +42 -0
  79. package/dist/webapi/lib/rsaes.js +24 -0
  80. package/dist/webapi/lib/signing.js +74 -0
  81. package/dist/webapi/lib/type_checks.js +41 -0
  82. package/dist/webapi/lib/validate_algorithms.js +10 -0
  83. package/dist/webapi/lib/validate_crit.js +33 -0
  84. package/dist/webapi/util/base64url.js +30 -0
  85. package/dist/webapi/util/decode_jwt.js +32 -0
  86. package/dist/webapi/util/decode_protected_header.js +34 -0
  87. package/dist/webapi/util/errors.js +99 -0
  88. package/package.json +195 -0
@@ -0,0 +1,101 @@
1
+ import { CompactEncrypt } from '../jwe/compact/encrypt.js';
2
+ import { JWTClaimsBuilder } from '../lib/jwt_claims_set.js';
3
+ import { assertNotSet } from '../lib/helpers.js';
4
+ export class EncryptJWT {
5
+ #cek;
6
+ #iv;
7
+ #keyManagementParameters;
8
+ #protectedHeader;
9
+ #replicateIssuerAsHeader;
10
+ #replicateSubjectAsHeader;
11
+ #replicateAudienceAsHeader;
12
+ #jwt;
13
+ constructor(payload = {}) {
14
+ this.#jwt = new JWTClaimsBuilder(payload);
15
+ }
16
+ setIssuer(issuer) {
17
+ this.#jwt.iss = issuer;
18
+ return this;
19
+ }
20
+ setSubject(subject) {
21
+ this.#jwt.sub = subject;
22
+ return this;
23
+ }
24
+ setAudience(audience) {
25
+ this.#jwt.aud = audience;
26
+ return this;
27
+ }
28
+ setJti(jwtId) {
29
+ this.#jwt.jti = jwtId;
30
+ return this;
31
+ }
32
+ setNotBefore(input) {
33
+ this.#jwt.nbf = input;
34
+ return this;
35
+ }
36
+ setExpirationTime(input) {
37
+ this.#jwt.exp = input;
38
+ return this;
39
+ }
40
+ setIssuedAt(input) {
41
+ this.#jwt.iat = input;
42
+ return this;
43
+ }
44
+ setProtectedHeader(protectedHeader) {
45
+ assertNotSet(this.#protectedHeader, 'setProtectedHeader');
46
+ this.#protectedHeader = protectedHeader;
47
+ return this;
48
+ }
49
+ setKeyManagementParameters(parameters) {
50
+ assertNotSet(this.#keyManagementParameters, 'setKeyManagementParameters');
51
+ this.#keyManagementParameters = parameters;
52
+ return this;
53
+ }
54
+ setContentEncryptionKey(cek) {
55
+ assertNotSet(this.#cek, 'setContentEncryptionKey');
56
+ this.#cek = cek;
57
+ return this;
58
+ }
59
+ setInitializationVector(iv) {
60
+ assertNotSet(this.#iv, 'setInitializationVector');
61
+ this.#iv = iv;
62
+ return this;
63
+ }
64
+ replicateIssuerAsHeader() {
65
+ this.#replicateIssuerAsHeader = true;
66
+ return this;
67
+ }
68
+ replicateSubjectAsHeader() {
69
+ this.#replicateSubjectAsHeader = true;
70
+ return this;
71
+ }
72
+ replicateAudienceAsHeader() {
73
+ this.#replicateAudienceAsHeader = true;
74
+ return this;
75
+ }
76
+ async encrypt(key, options) {
77
+ const enc = new CompactEncrypt(this.#jwt.data());
78
+ if (this.#protectedHeader &&
79
+ (this.#replicateIssuerAsHeader ||
80
+ this.#replicateSubjectAsHeader ||
81
+ this.#replicateAudienceAsHeader)) {
82
+ this.#protectedHeader = {
83
+ ...this.#protectedHeader,
84
+ iss: this.#replicateIssuerAsHeader ? this.#jwt.iss : undefined,
85
+ sub: this.#replicateSubjectAsHeader ? this.#jwt.sub : undefined,
86
+ aud: this.#replicateAudienceAsHeader ? this.#jwt.aud : undefined,
87
+ };
88
+ }
89
+ enc.setProtectedHeader(this.#protectedHeader);
90
+ if (this.#iv) {
91
+ enc.setInitializationVector(this.#iv);
92
+ }
93
+ if (this.#cek) {
94
+ enc.setContentEncryptionKey(this.#cek);
95
+ }
96
+ if (this.#keyManagementParameters) {
97
+ enc.setKeyManagementParameters(this.#keyManagementParameters);
98
+ }
99
+ return enc.encrypt(key, options);
100
+ }
101
+ }
@@ -0,0 +1,52 @@
1
+ import { CompactSign } from '../jws/compact/sign.js';
2
+ import { JWTInvalid } from '../util/errors.js';
3
+ import { JWTClaimsBuilder } from '../lib/jwt_claims_set.js';
4
+ export class SignJWT {
5
+ #protectedHeader;
6
+ #jwt;
7
+ constructor(payload = {}) {
8
+ this.#jwt = new JWTClaimsBuilder(payload);
9
+ }
10
+ setIssuer(issuer) {
11
+ this.#jwt.iss = issuer;
12
+ return this;
13
+ }
14
+ setSubject(subject) {
15
+ this.#jwt.sub = subject;
16
+ return this;
17
+ }
18
+ setAudience(audience) {
19
+ this.#jwt.aud = audience;
20
+ return this;
21
+ }
22
+ setJti(jwtId) {
23
+ this.#jwt.jti = jwtId;
24
+ return this;
25
+ }
26
+ setNotBefore(input) {
27
+ this.#jwt.nbf = input;
28
+ return this;
29
+ }
30
+ setExpirationTime(input) {
31
+ this.#jwt.exp = input;
32
+ return this;
33
+ }
34
+ setIssuedAt(input) {
35
+ this.#jwt.iat = input;
36
+ return this;
37
+ }
38
+ setProtectedHeader(protectedHeader) {
39
+ this.#protectedHeader = protectedHeader;
40
+ return this;
41
+ }
42
+ async sign(key, options) {
43
+ const sig = new CompactSign(this.#jwt.data());
44
+ sig.setProtectedHeader(this.#protectedHeader);
45
+ if (Array.isArray(this.#protectedHeader?.crit) &&
46
+ this.#protectedHeader.crit.includes('b64') &&
47
+ this.#protectedHeader.b64 === false) {
48
+ throw new JWTInvalid('JWTs MUST NOT use unencoded payload');
49
+ }
50
+ return sig.sign(key, options);
51
+ }
52
+ }
@@ -0,0 +1,63 @@
1
+ import * as b64u from '../util/base64url.js';
2
+ import { decoder } from '../lib/buffer_utils.js';
3
+ import { JWTInvalid } from '../util/errors.js';
4
+ import { validateClaimsSet, JWTClaimsBuilder } from '../lib/jwt_claims_set.js';
5
+ export class UnsecuredJWT {
6
+ #jwt;
7
+ constructor(payload = {}) {
8
+ this.#jwt = new JWTClaimsBuilder(payload);
9
+ }
10
+ encode() {
11
+ const header = b64u.encode(JSON.stringify({ alg: 'none' }));
12
+ const payload = b64u.encode(this.#jwt.data());
13
+ return `${header}.${payload}.`;
14
+ }
15
+ setIssuer(issuer) {
16
+ this.#jwt.iss = issuer;
17
+ return this;
18
+ }
19
+ setSubject(subject) {
20
+ this.#jwt.sub = subject;
21
+ return this;
22
+ }
23
+ setAudience(audience) {
24
+ this.#jwt.aud = audience;
25
+ return this;
26
+ }
27
+ setJti(jwtId) {
28
+ this.#jwt.jti = jwtId;
29
+ return this;
30
+ }
31
+ setNotBefore(input) {
32
+ this.#jwt.nbf = input;
33
+ return this;
34
+ }
35
+ setExpirationTime(input) {
36
+ this.#jwt.exp = input;
37
+ return this;
38
+ }
39
+ setIssuedAt(input) {
40
+ this.#jwt.iat = input;
41
+ return this;
42
+ }
43
+ static decode(jwt, options) {
44
+ if (typeof jwt !== 'string') {
45
+ throw new JWTInvalid('Unsecured JWT must be a string');
46
+ }
47
+ const { 0: encodedHeader, 1: encodedPayload, 2: signature, length } = jwt.split('.');
48
+ if (length !== 3 || signature !== '') {
49
+ throw new JWTInvalid('Invalid Unsecured JWT');
50
+ }
51
+ let header;
52
+ try {
53
+ header = JSON.parse(decoder.decode(b64u.decode(encodedHeader)));
54
+ if (header.alg !== 'none')
55
+ throw new Error();
56
+ }
57
+ catch {
58
+ throw new JWTInvalid('Invalid Unsecured JWT');
59
+ }
60
+ const payload = validateClaimsSet(header, b64u.decode(encodedPayload), options);
61
+ return { payload, header };
62
+ }
63
+ }
@@ -0,0 +1,15 @@
1
+ import { compactVerify } from '../jws/compact/verify.js';
2
+ import { validateClaimsSet } from '../lib/jwt_claims_set.js';
3
+ import { JWTInvalid } from '../util/errors.js';
4
+ export async function jwtVerify(jwt, key, options) {
5
+ const verified = await compactVerify(jwt, key, options);
6
+ if (verified.protectedHeader.crit?.includes('b64') && verified.protectedHeader.b64 === false) {
7
+ throw new JWTInvalid('JWTs MUST NOT use unencoded payload');
8
+ }
9
+ const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);
10
+ const result = { payload, protectedHeader: verified.protectedHeader };
11
+ if (typeof key === 'function') {
12
+ return { ...result, key: verified.key };
13
+ }
14
+ return result;
15
+ }
@@ -0,0 +1,11 @@
1
+ import { toSPKI as exportPublic, toPKCS8 as exportPrivate } from '../lib/asn1.js';
2
+ import { keyToJWK } from '../lib/key_to_jwk.js';
3
+ export async function exportSPKI(key) {
4
+ return exportPublic(key);
5
+ }
6
+ export async function exportPKCS8(key) {
7
+ return exportPrivate(key);
8
+ }
9
+ export async function exportJWK(key) {
10
+ return keyToJWK(key);
11
+ }
@@ -0,0 +1,97 @@
1
+ import { JOSENotSupported } from '../util/errors.js';
2
+ function getModulusLengthOption(options) {
3
+ const modulusLength = options?.modulusLength ?? 2048;
4
+ if (typeof modulusLength !== 'number' || modulusLength < 2048) {
5
+ throw new JOSENotSupported('Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used');
6
+ }
7
+ return modulusLength;
8
+ }
9
+ export async function generateKeyPair(alg, options) {
10
+ let algorithm;
11
+ let keyUsages;
12
+ switch (alg) {
13
+ case 'PS256':
14
+ case 'PS384':
15
+ case 'PS512':
16
+ algorithm = {
17
+ name: 'RSA-PSS',
18
+ hash: `SHA-${alg.slice(-3)}`,
19
+ publicExponent: Uint8Array.of(0x01, 0x00, 0x01),
20
+ modulusLength: getModulusLengthOption(options),
21
+ };
22
+ keyUsages = ['sign', 'verify'];
23
+ break;
24
+ case 'RS256':
25
+ case 'RS384':
26
+ case 'RS512':
27
+ algorithm = {
28
+ name: 'RSASSA-PKCS1-v1_5',
29
+ hash: `SHA-${alg.slice(-3)}`,
30
+ publicExponent: Uint8Array.of(0x01, 0x00, 0x01),
31
+ modulusLength: getModulusLengthOption(options),
32
+ };
33
+ keyUsages = ['sign', 'verify'];
34
+ break;
35
+ case 'RSA-OAEP':
36
+ case 'RSA-OAEP-256':
37
+ case 'RSA-OAEP-384':
38
+ case 'RSA-OAEP-512':
39
+ algorithm = {
40
+ name: 'RSA-OAEP',
41
+ hash: `SHA-${parseInt(alg.slice(-3), 10) || 1}`,
42
+ publicExponent: Uint8Array.of(0x01, 0x00, 0x01),
43
+ modulusLength: getModulusLengthOption(options),
44
+ };
45
+ keyUsages = ['decrypt', 'unwrapKey', 'encrypt', 'wrapKey'];
46
+ break;
47
+ case 'ES256':
48
+ algorithm = { name: 'ECDSA', namedCurve: 'P-256' };
49
+ keyUsages = ['sign', 'verify'];
50
+ break;
51
+ case 'ES384':
52
+ algorithm = { name: 'ECDSA', namedCurve: 'P-384' };
53
+ keyUsages = ['sign', 'verify'];
54
+ break;
55
+ case 'ES512':
56
+ algorithm = { name: 'ECDSA', namedCurve: 'P-521' };
57
+ keyUsages = ['sign', 'verify'];
58
+ break;
59
+ case 'Ed25519':
60
+ case 'EdDSA': {
61
+ keyUsages = ['sign', 'verify'];
62
+ algorithm = { name: 'Ed25519' };
63
+ break;
64
+ }
65
+ case 'ML-DSA-44':
66
+ case 'ML-DSA-65':
67
+ case 'ML-DSA-87': {
68
+ keyUsages = ['sign', 'verify'];
69
+ algorithm = { name: alg };
70
+ break;
71
+ }
72
+ case 'ECDH-ES':
73
+ case 'ECDH-ES+A128KW':
74
+ case 'ECDH-ES+A192KW':
75
+ case 'ECDH-ES+A256KW': {
76
+ keyUsages = ['deriveBits'];
77
+ const crv = options?.crv ?? 'P-256';
78
+ switch (crv) {
79
+ case 'P-256':
80
+ case 'P-384':
81
+ case 'P-521': {
82
+ algorithm = { name: 'ECDH', namedCurve: crv };
83
+ break;
84
+ }
85
+ case 'X25519':
86
+ algorithm = { name: 'X25519' };
87
+ break;
88
+ default:
89
+ throw new JOSENotSupported('Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, and X25519');
90
+ }
91
+ break;
92
+ }
93
+ default:
94
+ throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
95
+ }
96
+ return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, keyUsages);
97
+ }
@@ -0,0 +1,40 @@
1
+ import { JOSENotSupported } from '../util/errors.js';
2
+ export async function generateSecret(alg, options) {
3
+ let length;
4
+ let algorithm;
5
+ let keyUsages;
6
+ switch (alg) {
7
+ case 'HS256':
8
+ case 'HS384':
9
+ case 'HS512':
10
+ length = parseInt(alg.slice(-3), 10);
11
+ algorithm = { name: 'HMAC', hash: `SHA-${length}`, length };
12
+ keyUsages = ['sign', 'verify'];
13
+ break;
14
+ case 'A128CBC-HS256':
15
+ case 'A192CBC-HS384':
16
+ case 'A256CBC-HS512':
17
+ length = parseInt(alg.slice(-3), 10);
18
+ return crypto.getRandomValues(new Uint8Array(length >> 3));
19
+ case 'A128KW':
20
+ case 'A192KW':
21
+ case 'A256KW':
22
+ length = parseInt(alg.slice(1, 4), 10);
23
+ algorithm = { name: 'AES-KW', length };
24
+ keyUsages = ['wrapKey', 'unwrapKey'];
25
+ break;
26
+ case 'A128GCMKW':
27
+ case 'A192GCMKW':
28
+ case 'A256GCMKW':
29
+ case 'A128GCM':
30
+ case 'A192GCM':
31
+ case 'A256GCM':
32
+ length = parseInt(alg.slice(1, 4), 10);
33
+ algorithm = { name: 'AES-GCM', length };
34
+ keyUsages = ['encrypt', 'decrypt'];
35
+ break;
36
+ default:
37
+ throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
38
+ }
39
+ return crypto.subtle.generateKey(algorithm, options?.extractable ?? false, keyUsages);
40
+ }
@@ -0,0 +1,57 @@
1
+ import { decode as decodeBase64URL } from '../util/base64url.js';
2
+ import { fromSPKI, fromPKCS8, fromX509 } from '../lib/asn1.js';
3
+ import { jwkToKey } from '../lib/jwk_to_key.js';
4
+ import { JOSENotSupported } from '../util/errors.js';
5
+ import { isObject } from '../lib/type_checks.js';
6
+ export async function importSPKI(spki, alg, options) {
7
+ if (typeof spki !== 'string' || spki.indexOf('-----BEGIN PUBLIC KEY-----') !== 0) {
8
+ throw new TypeError('"spki" must be SPKI formatted string');
9
+ }
10
+ return fromSPKI(spki, alg, options);
11
+ }
12
+ export async function importX509(x509, alg, options) {
13
+ if (typeof x509 !== 'string' || x509.indexOf('-----BEGIN CERTIFICATE-----') !== 0) {
14
+ throw new TypeError('"x509" must be X.509 formatted string');
15
+ }
16
+ return fromX509(x509, alg, options);
17
+ }
18
+ export async function importPKCS8(pkcs8, alg, options) {
19
+ if (typeof pkcs8 !== 'string' || pkcs8.indexOf('-----BEGIN PRIVATE KEY-----') !== 0) {
20
+ throw new TypeError('"pkcs8" must be PKCS#8 formatted string');
21
+ }
22
+ return fromPKCS8(pkcs8, alg, options);
23
+ }
24
+ export async function importJWK(jwk, alg, options) {
25
+ if (!isObject(jwk)) {
26
+ throw new TypeError('JWK must be an object');
27
+ }
28
+ let ext;
29
+ alg ??= jwk.alg;
30
+ ext ??= options?.extractable ?? jwk.ext;
31
+ switch (jwk.kty) {
32
+ case 'oct':
33
+ if (typeof jwk.k !== 'string' || !jwk.k) {
34
+ throw new TypeError('missing "k" (Key Value) Parameter value');
35
+ }
36
+ return decodeBase64URL(jwk.k);
37
+ case 'RSA':
38
+ if ('oth' in jwk && jwk.oth !== undefined) {
39
+ throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
40
+ }
41
+ return jwkToKey({ ...jwk, alg, ext });
42
+ case 'AKP': {
43
+ if (typeof jwk.alg !== 'string' || !jwk.alg) {
44
+ throw new TypeError('missing "alg" (Algorithm) Parameter value');
45
+ }
46
+ if (alg !== undefined && alg !== jwk.alg) {
47
+ throw new TypeError('JWK alg and alg option value mismatch');
48
+ }
49
+ return jwkToKey({ ...jwk, ext });
50
+ }
51
+ case 'EC':
52
+ case 'OKP':
53
+ return jwkToKey({ ...jwk, alg, ext });
54
+ default:
55
+ throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
56
+ }
57
+ }
@@ -0,0 +1,15 @@
1
+ import { encrypt, decrypt } from './content_encryption.js';
2
+ import { encode as b64u } from '../util/base64url.js';
3
+ export async function wrap(alg, key, cek, iv) {
4
+ const jweAlgorithm = alg.slice(0, 7);
5
+ const wrapped = await encrypt(jweAlgorithm, cek, key, iv, new Uint8Array());
6
+ return {
7
+ encryptedKey: wrapped.ciphertext,
8
+ iv: b64u(wrapped.iv),
9
+ tag: b64u(wrapped.tag),
10
+ };
11
+ }
12
+ export async function unwrap(alg, key, encryptedKey, iv, tag) {
13
+ const jweAlgorithm = alg.slice(0, 7);
14
+ return decrypt(jweAlgorithm, key, encryptedKey, iv, tag, new Uint8Array());
15
+ }
@@ -0,0 +1,25 @@
1
+ import { checkEncCryptoKey } from './crypto_key.js';
2
+ function checkKeySize(key, alg) {
3
+ if (key.algorithm.length !== parseInt(alg.slice(1, 4), 10)) {
4
+ throw new TypeError(`Invalid key size for alg: ${alg}`);
5
+ }
6
+ }
7
+ function getCryptoKey(key, alg, usage) {
8
+ if (key instanceof Uint8Array) {
9
+ return crypto.subtle.importKey('raw', key, 'AES-KW', true, [usage]);
10
+ }
11
+ checkEncCryptoKey(key, alg, usage);
12
+ return key;
13
+ }
14
+ export async function wrap(alg, key, cek) {
15
+ const cryptoKey = await getCryptoKey(key, alg, 'wrapKey');
16
+ checkKeySize(cryptoKey, alg);
17
+ const cryptoKeyCek = await crypto.subtle.importKey('raw', cek, { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']);
18
+ return new Uint8Array(await crypto.subtle.wrapKey('raw', cryptoKeyCek, cryptoKey, 'AES-KW'));
19
+ }
20
+ export async function unwrap(alg, key, encryptedKey) {
21
+ const cryptoKey = await getCryptoKey(key, alg, 'unwrapKey');
22
+ checkKeySize(cryptoKey, alg);
23
+ const cryptoKeyCek = await crypto.subtle.unwrapKey('raw', encryptedKey, cryptoKey, 'AES-KW', { hash: 'SHA-256', name: 'HMAC' }, true, ['sign']);
24
+ return new Uint8Array(await crypto.subtle.exportKey('raw', cryptoKeyCek));
25
+ }