@hpke/cose 0.0.0-stage → 0.0.1

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 (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -2
  3. package/esm/mod.d.ts +16 -0
  4. package/esm/mod.d.ts.map +1 -0
  5. package/esm/mod.js +11 -0
  6. package/esm/package.json +3 -0
  7. package/esm/src/alg.d.ts +60 -0
  8. package/esm/src/alg.d.ts.map +1 -0
  9. package/esm/src/alg.js +96 -0
  10. package/esm/src/cbor/decoder.d.ts +4 -0
  11. package/esm/src/cbor/decoder.d.ts.map +1 -0
  12. package/esm/src/cbor/decoder.js +148 -0
  13. package/esm/src/cbor/encoder.d.ts +6 -0
  14. package/esm/src/cbor/encoder.d.ts.map +1 -0
  15. package/esm/src/cbor/encoder.js +109 -0
  16. package/esm/src/cbor/types.d.ts +8 -0
  17. package/esm/src/cbor/types.d.ts.map +1 -0
  18. package/esm/src/cbor/types.js +1 -0
  19. package/esm/src/contentAesGcm.d.ts +3 -0
  20. package/esm/src/contentAesGcm.d.ts.map +1 -0
  21. package/esm/src/contentAesGcm.js +30 -0
  22. package/esm/src/coseKey.d.ts +56 -0
  23. package/esm/src/coseKey.d.ts.map +1 -0
  24. package/esm/src/coseKey.js +185 -0
  25. package/esm/src/encrypt.d.ts +155 -0
  26. package/esm/src/encrypt.d.ts.map +1 -0
  27. package/esm/src/encrypt.js +317 -0
  28. package/esm/src/encrypt0.d.ts +91 -0
  29. package/esm/src/encrypt0.d.ts.map +1 -0
  30. package/esm/src/encrypt0.js +203 -0
  31. package/esm/src/errors.d.ts +5 -0
  32. package/esm/src/errors.d.ts.map +1 -0
  33. package/esm/src/errors.js +7 -0
  34. package/esm/src/hpke0.d.ts +8 -0
  35. package/esm/src/hpke0.d.ts.map +1 -0
  36. package/esm/src/hpke0.js +23 -0
  37. package/esm/src/hpke1.d.ts +8 -0
  38. package/esm/src/hpke1.d.ts.map +1 -0
  39. package/esm/src/hpke1.js +23 -0
  40. package/esm/src/hpke2.d.ts +8 -0
  41. package/esm/src/hpke2.d.ts.map +1 -0
  42. package/esm/src/hpke2.js +23 -0
  43. package/esm/src/hpke3.d.ts +8 -0
  44. package/esm/src/hpke3.d.ts.map +1 -0
  45. package/esm/src/hpke3.js +23 -0
  46. package/esm/src/hpke4.d.ts +8 -0
  47. package/esm/src/hpke4.d.ts.map +1 -0
  48. package/esm/src/hpke4.js +39 -0
  49. package/esm/src/hpke5.d.ts +8 -0
  50. package/esm/src/hpke5.d.ts.map +1 -0
  51. package/esm/src/hpke5.js +24 -0
  52. package/esm/src/hpke6.d.ts +8 -0
  53. package/esm/src/hpke6.d.ts.map +1 -0
  54. package/esm/src/hpke6.js +40 -0
  55. package/esm/src/hpke7.d.ts +8 -0
  56. package/esm/src/hpke7.d.ts.map +1 -0
  57. package/esm/src/hpke7.js +23 -0
  58. package/esm/src/structures.d.ts +41 -0
  59. package/esm/src/structures.d.ts.map +1 -0
  60. package/esm/src/structures.js +63 -0
  61. package/package.json +48 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Ajitomi Daisuke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,70 @@
1
- # Temporary Holding Version
1
+ # @hpke/cose
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A TypeScript implementation of
4
+ [COSE-HPKE (draft-ietf-cose-hpke)](https://datatracker.ietf.org/doc/draft-ietf-cose-hpke/)
5
+ built on top of
6
+ [@hpke/core](https://github.com/dajiaji/hpke-js/tree/main/packages/core). It is
7
+ tested against the test vectors in
8
+ [draft-ietf-cose-hpke-27](https://datatracker.ietf.org/doc/html/draft-ietf-cose-hpke-27).
9
+
10
+ ## Features
11
+
12
+ - **COSE_Encrypt0** (Integrated Encryption) — single-recipient HPKE encryption
13
+ directly into the COSE_Encrypt0 structure.
14
+ - **COSE_Encrypt** (Key Encryption) — multi-recipient HPKE key wrapping with a
15
+ content encryption key.
16
+
17
+ ## Supported Environments
18
+
19
+ This package is distributed as ESM only. On Node.js, version 20 or later is
20
+ required.
21
+
22
+ ## Supported Algorithms
23
+
24
+ | Name | COSE Value | KEM | KDF | AEAD |
25
+ | ------ | ---------- | -------------------------- | ----------- | ---------------- |
26
+ | HPKE-0 | 35 | DHKEM(P-256, HKDF-SHA256) | HKDF-SHA256 | AES-128-GCM |
27
+ | HPKE-1 | 37 | DHKEM(P-384, HKDF-SHA384) | HKDF-SHA384 | AES-256-GCM |
28
+ | HPKE-2 | 39 | DHKEM(P-521, HKDF-SHA512) | HKDF-SHA512 | AES-256-GCM |
29
+ | HPKE-3 | 41 | DHKEM(X25519, HKDF-SHA256) | HKDF-SHA256 | AES-128-GCM |
30
+ | HPKE-4 | 42 | DHKEM(X25519, HKDF-SHA256) | HKDF-SHA256 | ChaCha20Poly1305 |
31
+ | HPKE-5 | 43 | DHKEM(X448, HKDF-SHA512) | HKDF-SHA512 | AES-256-GCM |
32
+ | HPKE-6 | 44 | DHKEM(X448, HKDF-SHA512) | HKDF-SHA512 | ChaCha20Poly1305 |
33
+ | HPKE-7 | 45 | DHKEM(P-256, HKDF-SHA256) | HKDF-SHA256 | AES-256-GCM |
34
+
35
+ Key Encryption variants (HPKE-0-KE through HPKE-7-KE) use COSE values 46–53.
36
+
37
+ ## Usage
38
+
39
+ ### COSE_Encrypt0 (Integrated Encryption)
40
+
41
+ ```ts
42
+ import { createHpke3 } from "@hpke/cose";
43
+
44
+ const enc0 = createHpke3();
45
+ const rkp = await enc0.suite.kem.generateKeyPair();
46
+
47
+ const ct = await enc0.seal(rkp.publicKey, new TextEncoder().encode("hello"));
48
+ const pt = await enc0.open(rkp, ct);
49
+ // new TextDecoder().decode(pt) === "hello"
50
+ ```
51
+
52
+ ### COSE_Encrypt (Key Encryption)
53
+
54
+ ```ts
55
+ import { ContentAlg, createHpke3Ke } from "@hpke/cose";
56
+
57
+ const enc = createHpke3Ke(ContentAlg.A128GCM);
58
+ const rkp = await enc.generateKemKeyPair();
59
+
60
+ const ct = await enc.seal(
61
+ [{ recipientPublicKey: rkp.publicKey }],
62
+ new TextEncoder().encode("hello"),
63
+ );
64
+ const pt = await enc.open(rkp, ct);
65
+ // new TextDecoder().decode(pt) === "hello"
66
+ ```
67
+
68
+ ## License
69
+
70
+ MIT
package/esm/mod.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ export { ContentAlg, CoseHpkeAlg } from "./src/alg.js";
2
+ export type { CoseEncrypt0, CoseEncrypt0DetachedResult, CoseEncrypt0Options, } from "./src/encrypt0.js";
3
+ export type { CoseEncrypt } from "./src/encrypt.js";
4
+ export type { ContentCrypto, CoseEncryptDetachedResult, CoseEncryptOpenOptions, CoseEncryptSealOptions, CoseRecipient, } from "./src/encrypt.js";
5
+ export { CoseError } from "./src/errors.js";
6
+ export { buildEc2CoseKey, buildOkpCoseKey, CoseCrv, CoseKty, extractCurve, extractPrivateKeyBytes, extractPublicKeyBytes, } from "./src/coseKey.js";
7
+ export type { CoseKeyBuildOptions } from "./src/coseKey.js";
8
+ export { createHpke0, createHpke0Ke } from "./src/hpke0.js";
9
+ export { createHpke1, createHpke1Ke } from "./src/hpke1.js";
10
+ export { createHpke2, createHpke2Ke } from "./src/hpke2.js";
11
+ export { createHpke3, createHpke3Ke } from "./src/hpke3.js";
12
+ export { createHpke4, createHpke4Ke } from "./src/hpke4.js";
13
+ export { createHpke5, createHpke5Ke } from "./src/hpke5.js";
14
+ export { createHpke6, createHpke6Ke } from "./src/hpke6.js";
15
+ export { createHpke7, createHpke7Ke } from "./src/hpke7.js";
16
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EACV,YAAY,EACZ,0BAA0B,EAC1B,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EACV,aAAa,EACb,yBAAyB,EACzB,sBAAsB,EACtB,sBAAsB,EACtB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EACL,eAAe,EACf,eAAe,EACf,OAAO,EACP,OAAO,EACP,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
package/esm/mod.js ADDED
@@ -0,0 +1,11 @@
1
+ export { ContentAlg, CoseHpkeAlg } from "./src/alg.js";
2
+ export { CoseError } from "./src/errors.js";
3
+ export { buildEc2CoseKey, buildOkpCoseKey, CoseCrv, CoseKty, extractCurve, extractPrivateKeyBytes, extractPublicKeyBytes, } from "./src/coseKey.js";
4
+ export { createHpke0, createHpke0Ke } from "./src/hpke0.js";
5
+ export { createHpke1, createHpke1Ke } from "./src/hpke1.js";
6
+ export { createHpke2, createHpke2Ke } from "./src/hpke2.js";
7
+ export { createHpke3, createHpke3Ke } from "./src/hpke3.js";
8
+ export { createHpke4, createHpke4Ke } from "./src/hpke4.js";
9
+ export { createHpke5, createHpke5Ke } from "./src/hpke5.js";
10
+ export { createHpke6, createHpke6Ke } from "./src/hpke6.js";
11
+ export { createHpke7, createHpke7Ke } from "./src/hpke7.js";
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * COSE HPKE algorithm identifiers from draft-ietf-cose-hpke-27.
3
+ *
4
+ * Integrated Encryption (COSE_Encrypt0): values 35–45.
5
+ * Key Encryption (COSE_Encrypt): values 46–53.
6
+ */
7
+ export declare const CoseHpkeAlg: {
8
+ /** DHKEM(P-256), HKDF-SHA256, AES-128-GCM */
9
+ readonly HPKE_0: 35;
10
+ /** DHKEM(P-384), HKDF-SHA384, AES-256-GCM */
11
+ readonly HPKE_1: 37;
12
+ /** DHKEM(P-521), HKDF-SHA512, AES-256-GCM */
13
+ readonly HPKE_2: 39;
14
+ /** DHKEM(X25519), HKDF-SHA256, AES-128-GCM */
15
+ readonly HPKE_3: 41;
16
+ /** DHKEM(X25519), HKDF-SHA256, ChaCha20Poly1305 */
17
+ readonly HPKE_4: 42;
18
+ /** DHKEM(X448), HKDF-SHA512, AES-256-GCM */
19
+ readonly HPKE_5: 43;
20
+ /** DHKEM(X448), HKDF-SHA512, ChaCha20Poly1305 */
21
+ readonly HPKE_6: 44;
22
+ /** DHKEM(P-256), HKDF-SHA256, AES-256-GCM */
23
+ readonly HPKE_7: 45;
24
+ /** Key Encryption: DHKEM(P-256), HKDF-SHA256, AES-128-GCM */
25
+ readonly HPKE_0_KE: 46;
26
+ /** Key Encryption: DHKEM(P-384), HKDF-SHA384, AES-256-GCM */
27
+ readonly HPKE_1_KE: 47;
28
+ /** Key Encryption: DHKEM(P-521), HKDF-SHA512, AES-256-GCM */
29
+ readonly HPKE_2_KE: 48;
30
+ /** Key Encryption: DHKEM(X25519), HKDF-SHA256, AES-128-GCM */
31
+ readonly HPKE_3_KE: 49;
32
+ /** Key Encryption: DHKEM(X25519), HKDF-SHA256, ChaCha20Poly1305 */
33
+ readonly HPKE_4_KE: 50;
34
+ /** Key Encryption: DHKEM(X448), HKDF-SHA512, AES-256-GCM */
35
+ readonly HPKE_5_KE: 51;
36
+ /** Key Encryption: DHKEM(X448), HKDF-SHA512, ChaCha20Poly1305 */
37
+ readonly HPKE_6_KE: 52;
38
+ /** Key Encryption: DHKEM(P-256), HKDF-SHA256, AES-256-GCM */
39
+ readonly HPKE_7_KE: 53;
40
+ };
41
+ export type CoseHpkeAlg = (typeof CoseHpkeAlg)[keyof typeof CoseHpkeAlg];
42
+ /** COSE content-encryption algorithm identifiers. */
43
+ export declare const ContentAlg: {
44
+ /** AES-128-GCM (COSE alg value 1) */
45
+ readonly A128GCM: 1;
46
+ /** AES-256-GCM (COSE alg value 3) */
47
+ readonly A256GCM: 3;
48
+ /** ChaCha20/Poly1305 (COSE alg value 24) */
49
+ readonly CHACHA20POLY1305: 24;
50
+ };
51
+ export type ContentAlg = (typeof ContentAlg)[keyof typeof ContentAlg];
52
+ /** Content key sizes in bytes for each ContentAlg. */
53
+ export declare function contentKeySize(alg: ContentAlg): number;
54
+ /** Content nonce sizes in bytes for each ContentAlg. */
55
+ export declare function contentNonceSize(_alg: ContentAlg): number;
56
+ /** Whether the algorithm is for Key Encryption (COSE_Encrypt). */
57
+ export declare function isKeyEncryption(alg: CoseHpkeAlg): boolean;
58
+ /** Whether the algorithm is for Integrated Encryption (COSE_Encrypt0). */
59
+ export declare function isIntegratedEncryption(alg: CoseHpkeAlg): boolean;
60
+ //# sourceMappingURL=alg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alg.d.ts","sourceRoot":"","sources":["../../src/src/alg.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,WAAW;IACtB,6CAA6C;;IAE7C,6CAA6C;;IAE7C,6CAA6C;;IAE7C,8CAA8C;;IAE9C,mDAAmD;;IAEnD,4CAA4C;;IAE5C,iDAAiD;;IAEjD,6CAA6C;;IAE7C,6DAA6D;;IAE7D,6DAA6D;;IAE7D,6DAA6D;;IAE7D,8DAA8D;;IAE9D,mEAAmE;;IAEnE,4DAA4D;;IAE5D,iEAAiE;;IAEjE,6DAA6D;;CAErD,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAEzE,qDAAqD;AACrD,eAAO,MAAM,UAAU;IACrB,qCAAqC;;IAErC,qCAAqC;;IAErC,4CAA4C;;CAEpC,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAEtE,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAWtD;AAED,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAGzD;AAuBD,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAEzD;AAED,0EAA0E;AAC1E,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAEhE"}
package/esm/src/alg.js ADDED
@@ -0,0 +1,96 @@
1
+ import { CoseError } from "./errors.js";
2
+ /**
3
+ * COSE HPKE algorithm identifiers from draft-ietf-cose-hpke-27.
4
+ *
5
+ * Integrated Encryption (COSE_Encrypt0): values 35–45.
6
+ * Key Encryption (COSE_Encrypt): values 46–53.
7
+ */
8
+ export const CoseHpkeAlg = {
9
+ /** DHKEM(P-256), HKDF-SHA256, AES-128-GCM */
10
+ HPKE_0: 35,
11
+ /** DHKEM(P-384), HKDF-SHA384, AES-256-GCM */
12
+ HPKE_1: 37,
13
+ /** DHKEM(P-521), HKDF-SHA512, AES-256-GCM */
14
+ HPKE_2: 39,
15
+ /** DHKEM(X25519), HKDF-SHA256, AES-128-GCM */
16
+ HPKE_3: 41,
17
+ /** DHKEM(X25519), HKDF-SHA256, ChaCha20Poly1305 */
18
+ HPKE_4: 42,
19
+ /** DHKEM(X448), HKDF-SHA512, AES-256-GCM */
20
+ HPKE_5: 43,
21
+ /** DHKEM(X448), HKDF-SHA512, ChaCha20Poly1305 */
22
+ HPKE_6: 44,
23
+ /** DHKEM(P-256), HKDF-SHA256, AES-256-GCM */
24
+ HPKE_7: 45,
25
+ /** Key Encryption: DHKEM(P-256), HKDF-SHA256, AES-128-GCM */
26
+ HPKE_0_KE: 46,
27
+ /** Key Encryption: DHKEM(P-384), HKDF-SHA384, AES-256-GCM */
28
+ HPKE_1_KE: 47,
29
+ /** Key Encryption: DHKEM(P-521), HKDF-SHA512, AES-256-GCM */
30
+ HPKE_2_KE: 48,
31
+ /** Key Encryption: DHKEM(X25519), HKDF-SHA256, AES-128-GCM */
32
+ HPKE_3_KE: 49,
33
+ /** Key Encryption: DHKEM(X25519), HKDF-SHA256, ChaCha20Poly1305 */
34
+ HPKE_4_KE: 50,
35
+ /** Key Encryption: DHKEM(X448), HKDF-SHA512, AES-256-GCM */
36
+ HPKE_5_KE: 51,
37
+ /** Key Encryption: DHKEM(X448), HKDF-SHA512, ChaCha20Poly1305 */
38
+ HPKE_6_KE: 52,
39
+ /** Key Encryption: DHKEM(P-256), HKDF-SHA256, AES-256-GCM */
40
+ HPKE_7_KE: 53,
41
+ };
42
+ /** COSE content-encryption algorithm identifiers. */
43
+ export const ContentAlg = {
44
+ /** AES-128-GCM (COSE alg value 1) */
45
+ A128GCM: 1,
46
+ /** AES-256-GCM (COSE alg value 3) */
47
+ A256GCM: 3,
48
+ /** ChaCha20/Poly1305 (COSE alg value 24) */
49
+ CHACHA20POLY1305: 24,
50
+ };
51
+ /** Content key sizes in bytes for each ContentAlg. */
52
+ export function contentKeySize(alg) {
53
+ switch (alg) {
54
+ case ContentAlg.A128GCM:
55
+ return 16;
56
+ case ContentAlg.A256GCM:
57
+ return 32;
58
+ case ContentAlg.CHACHA20POLY1305:
59
+ return 32;
60
+ default:
61
+ throw new CoseError(`Unsupported content algorithm: ${alg}`);
62
+ }
63
+ }
64
+ /** Content nonce sizes in bytes for each ContentAlg. */
65
+ export function contentNonceSize(_alg) {
66
+ // AES-128-GCM, AES-256-GCM, and ChaCha20/Poly1305 all use 12-byte nonces
67
+ return 12;
68
+ }
69
+ const KEY_ENCRYPTION_ALGS = new Set([
70
+ 46,
71
+ 47,
72
+ 48,
73
+ 49,
74
+ 50,
75
+ 51,
76
+ 52,
77
+ 53,
78
+ ]);
79
+ const INTEGRATED_ENCRYPTION_ALGS = new Set([
80
+ 35,
81
+ 37,
82
+ 39,
83
+ 41,
84
+ 42,
85
+ 43,
86
+ 44,
87
+ 45,
88
+ ]);
89
+ /** Whether the algorithm is for Key Encryption (COSE_Encrypt). */
90
+ export function isKeyEncryption(alg) {
91
+ return KEY_ENCRYPTION_ALGS.has(alg);
92
+ }
93
+ /** Whether the algorithm is for Integrated Encryption (COSE_Encrypt0). */
94
+ export function isIntegratedEncryption(alg) {
95
+ return INTEGRATED_ENCRYPTION_ALGS.has(alg);
96
+ }
@@ -0,0 +1,4 @@
1
+ import type { CborValue } from "./types.js";
2
+ /** Decode a CBOR byte string into a CborValue. */
3
+ export declare function decode(data: Uint8Array): CborValue;
4
+ //# sourceMappingURL=decoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../../src/src/cbor/decoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA+I5C,kDAAkD;AAClD,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,CAOlD"}
@@ -0,0 +1,148 @@
1
+ /** Maximum nesting depth of data items. COSE structures stay far below this. */
2
+ const MAX_NESTING_DEPTH = 32;
3
+ class Decoder {
4
+ constructor(data) {
5
+ Object.defineProperty(this, "_data", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: void 0
10
+ });
11
+ Object.defineProperty(this, "_pos", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ Object.defineProperty(this, "_depth", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: void 0
22
+ });
23
+ this._data = data;
24
+ this._pos = 0;
25
+ this._depth = 0;
26
+ }
27
+ get position() {
28
+ return this._pos;
29
+ }
30
+ decode() {
31
+ if (this._depth >= MAX_NESTING_DEPTH) {
32
+ throw new Error("CBOR: nesting too deep");
33
+ }
34
+ this._depth++;
35
+ const value = this._decodeItem();
36
+ this._depth--;
37
+ return value;
38
+ }
39
+ _decodeItem() {
40
+ if (this._pos >= this._data.length) {
41
+ throw new Error("CBOR: unexpected end of input");
42
+ }
43
+ const initial = this._data[this._pos++];
44
+ const major = initial >> 5;
45
+ const additional = initial & 0x1f;
46
+ switch (major) {
47
+ case 0: // unsigned int
48
+ return this._readUint(additional);
49
+ case 1: // negative int
50
+ return -1 - this._readUint(additional);
51
+ case 2: // byte string
52
+ return this._readBytes(this._readUint(additional));
53
+ case 3: // text string
54
+ return this._readText(this._readUint(additional));
55
+ case 4: // array
56
+ return this._readArray(this._readUint(additional));
57
+ case 5: // map
58
+ return this._readMap(this._readUint(additional));
59
+ case 6: // tag (skip tag number, return inner value)
60
+ this._readUint(additional);
61
+ return this.decode();
62
+ case 7: // simple/float
63
+ if (additional === 22) {
64
+ return null;
65
+ }
66
+ throw new Error(`CBOR: unsupported simple value ${additional}`);
67
+ default:
68
+ throw new Error(`CBOR: unsupported major type ${major}`);
69
+ }
70
+ }
71
+ _readUint(additional) {
72
+ if (additional < 24) {
73
+ return additional;
74
+ }
75
+ if (additional === 24) {
76
+ return this._data[this._pos++];
77
+ }
78
+ if (additional === 25) {
79
+ const val = (this._data[this._pos] << 8) | this._data[this._pos + 1];
80
+ this._pos += 2;
81
+ return val;
82
+ }
83
+ if (additional === 26) {
84
+ const val = (this._data[this._pos] << 24) |
85
+ (this._data[this._pos + 1] << 16) |
86
+ (this._data[this._pos + 2] << 8) |
87
+ this._data[this._pos + 3];
88
+ this._pos += 4;
89
+ return val >>> 0; // unsigned
90
+ }
91
+ if (additional === 27) {
92
+ const dv = new DataView(this._data.buffer, this._data.byteOffset + this._pos, 8);
93
+ const val = dv.getBigUint64(0);
94
+ this._pos += 8;
95
+ if (val > BigInt(Number.MAX_SAFE_INTEGER)) {
96
+ throw new Error("CBOR: integer too large for number");
97
+ }
98
+ return Number(val);
99
+ }
100
+ throw new Error(`CBOR: unsupported additional info ${additional}`);
101
+ }
102
+ _readBytes(len) {
103
+ const slice = this._data.slice(this._pos, this._pos + len);
104
+ this._pos += len;
105
+ return slice;
106
+ }
107
+ _readText(len) {
108
+ const bytes = this._readBytes(len);
109
+ try {
110
+ return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
111
+ }
112
+ catch {
113
+ throw new Error("CBOR: invalid UTF-8 in text string");
114
+ }
115
+ }
116
+ _readArray(len) {
117
+ const arr = [];
118
+ for (let i = 0; i < len; i++) {
119
+ arr.push(this.decode());
120
+ }
121
+ return arr;
122
+ }
123
+ _readMap(len) {
124
+ const map = new Map();
125
+ for (let i = 0; i < len; i++) {
126
+ const key = this.decode();
127
+ if (typeof key !== "number" && typeof key !== "string") {
128
+ throw new Error("CBOR: unsupported map key type");
129
+ }
130
+ // RFC 9052 Section 3: a message with a repeated label MUST be rejected.
131
+ if (map.has(key)) {
132
+ throw new Error("CBOR: duplicate map key");
133
+ }
134
+ const val = this.decode();
135
+ map.set(key, val);
136
+ }
137
+ return map;
138
+ }
139
+ }
140
+ /** Decode a CBOR byte string into a CborValue. */
141
+ export function decode(data) {
142
+ const decoder = new Decoder(data);
143
+ const value = decoder.decode();
144
+ if (decoder.position !== data.length) {
145
+ throw new Error("CBOR: trailing bytes after decoded value");
146
+ }
147
+ return value;
148
+ }
@@ -0,0 +1,6 @@
1
+ import type { CborValue } from "./types.js";
2
+ /** Encode a CborValue into a CBOR byte string. */
3
+ export declare function encode(value: CborValue): Uint8Array;
4
+ /** Encode a CborValue wrapped in a CBOR tag (major type 6). */
5
+ export declare function encodeTagged(tag: number, value: CborValue): Uint8Array;
6
+ //# sourceMappingURL=encoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../../src/src/cbor/encoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAkH5C,kDAAkD;AAClD,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,CAEnD;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,UAAU,CAEtE"}
@@ -0,0 +1,109 @@
1
+ function encodeHead(major, value) {
2
+ const mt = major << 5;
3
+ if (value < 24) {
4
+ return new Uint8Array([mt | value]);
5
+ }
6
+ if (value < 0x100) {
7
+ return new Uint8Array([mt | 24, value]);
8
+ }
9
+ if (value < 0x10000) {
10
+ const buf = new Uint8Array(3);
11
+ buf[0] = mt | 25;
12
+ buf[1] = (value >> 8) & 0xff;
13
+ buf[2] = value & 0xff;
14
+ return buf;
15
+ }
16
+ if (value < 0x100000000) {
17
+ const buf = new Uint8Array(5);
18
+ buf[0] = mt | 26;
19
+ buf[1] = (value >> 24) & 0xff;
20
+ buf[2] = (value >> 16) & 0xff;
21
+ buf[3] = (value >> 8) & 0xff;
22
+ buf[4] = value & 0xff;
23
+ return buf;
24
+ }
25
+ // 64-bit: use DataView for values > 32 bits
26
+ const buf = new Uint8Array(9);
27
+ buf[0] = mt | 27;
28
+ const dv = new DataView(buf.buffer);
29
+ dv.setBigUint64(1, BigInt(value));
30
+ return buf;
31
+ }
32
+ function encodeValue(value) {
33
+ if (value === null) {
34
+ return [new Uint8Array([0xf6])]; // major 7, simple value 22
35
+ }
36
+ if (typeof value === "number") {
37
+ if (!Number.isInteger(value)) {
38
+ throw new Error("CBOR: float encoding is not supported");
39
+ }
40
+ if (value >= 0) {
41
+ return [encodeHead(0, value)]; // major 0: unsigned int
42
+ }
43
+ // negative int: major 1, value = -1 - n
44
+ return [encodeHead(1, -1 - value)];
45
+ }
46
+ if (typeof value === "string") {
47
+ const encoded = new TextEncoder().encode(value);
48
+ return [encodeHead(3, encoded.length), encoded]; // major 3: text string
49
+ }
50
+ if (value instanceof Uint8Array) {
51
+ return [encodeHead(2, value.length), value]; // major 2: byte string
52
+ }
53
+ if (Array.isArray(value)) {
54
+ const parts = [encodeHead(4, value.length)]; // major 4: array
55
+ for (const item of value) {
56
+ parts.push(...encodeValue(item));
57
+ }
58
+ return parts;
59
+ }
60
+ if (value instanceof Map) {
61
+ // COSE deterministic encoding: sort by encoded key bytes (lexicographic)
62
+ const entries = [];
63
+ for (const [k, v] of value) {
64
+ const keyParts = encodeValue(k);
65
+ const keyBytes = concat(keyParts);
66
+ entries.push({ keyBytes, valParts: encodeValue(v) });
67
+ }
68
+ entries.sort((a, b) => compareBytes(a.keyBytes, b.keyBytes));
69
+ const parts = [encodeHead(5, entries.length)]; // major 5: map
70
+ for (const entry of entries) {
71
+ parts.push(entry.keyBytes);
72
+ for (const vp of entry.valParts) {
73
+ parts.push(vp);
74
+ }
75
+ }
76
+ return parts;
77
+ }
78
+ throw new Error("CBOR: unsupported value type");
79
+ }
80
+ function compareBytes(a, b) {
81
+ const len = Math.min(a.length, b.length);
82
+ for (let i = 0; i < len; i++) {
83
+ if (a[i] !== b[i]) {
84
+ return a[i] - b[i];
85
+ }
86
+ }
87
+ return a.length - b.length;
88
+ }
89
+ function concat(parts) {
90
+ let total = 0;
91
+ for (const p of parts) {
92
+ total += p.length;
93
+ }
94
+ const result = new Uint8Array(total);
95
+ let offset = 0;
96
+ for (const p of parts) {
97
+ result.set(p, offset);
98
+ offset += p.length;
99
+ }
100
+ return result;
101
+ }
102
+ /** Encode a CborValue into a CBOR byte string. */
103
+ export function encode(value) {
104
+ return concat(encodeValue(value));
105
+ }
106
+ /** Encode a CborValue wrapped in a CBOR tag (major type 6). */
107
+ export function encodeTagged(tag, value) {
108
+ return concat([encodeHead(6, tag), ...encodeValue(value)]);
109
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A CBOR value that can be encoded/decoded by the minimal CBOR codec.
3
+ *
4
+ * Supported types: unsigned integer, negative integer, byte string,
5
+ * text string, array, map (with integer or text keys), and null.
6
+ */
7
+ export type CborValue = number | Uint8Array | string | CborValue[] | Map<CborValue, CborValue> | null;
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/src/cbor/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,UAAU,GACV,MAAM,GACN,SAAS,EAAE,GACX,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,GACzB,IAAI,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { ContentCrypto } from "./encrypt.js";
2
+ export declare const aesGcmContentCrypto: ContentCrypto;
3
+ //# sourceMappingURL=contentAesGcm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contentAesGcm.d.ts","sourceRoot":"","sources":["../../src/src/contentAesGcm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAUlD,eAAO,MAAM,mBAAmB,EAAE,aAqCjC,CAAC"}
@@ -0,0 +1,30 @@
1
+ /** Convert Uint8Array → ArrayBuffer (handles subarrays). */
2
+ function ab(u) {
3
+ return u.buffer.slice(u.byteOffset, u.byteOffset + u.byteLength);
4
+ }
5
+ export const aesGcmContentCrypto = {
6
+ async seal(key, nonce, plaintext, aad) {
7
+ const s = globalThis.crypto.subtle;
8
+ const k = await s.importKey("raw", ab(key), "AES-GCM", false, [
9
+ "encrypt",
10
+ ]);
11
+ return new Uint8Array(await s.encrypt({
12
+ name: "AES-GCM",
13
+ iv: ab(nonce),
14
+ additionalData: ab(aad),
15
+ tagLength: 128,
16
+ }, k, ab(plaintext)));
17
+ },
18
+ async open(key, nonce, ciphertext, aad) {
19
+ const s = globalThis.crypto.subtle;
20
+ const k = await s.importKey("raw", ab(key), "AES-GCM", false, [
21
+ "decrypt",
22
+ ]);
23
+ return new Uint8Array(await s.decrypt({
24
+ name: "AES-GCM",
25
+ iv: ab(nonce),
26
+ additionalData: ab(aad),
27
+ tagLength: 128,
28
+ }, k, ab(ciphertext)));
29
+ },
30
+ };