@pamoja/session 0.1.15 → 0.1.16

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.
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Ergonomic facade over the generated session binding.
3
+ *
4
+ * Two devices that already know each other's public keys can agree on a session
5
+ * key without ever sending it, and then exchange messages that are confidential,
6
+ * cannot be altered undetected, and cannot be replayed. That is the whole of
7
+ * what a small device usually needs from transport security, at a fraction of
8
+ * what a TLS stack costs it.
9
+ *
10
+ * The role is re-exported as a runtime {@link Role} object, because the
11
+ * generated enum is types-only.
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ import type { Role as RoleName } from '@pamoja/native';
16
+ import { AgreementKey as NativeAgreementKey, type SealedMessage } from '@pamoja/native';
17
+ export { AgreementKey } from '@pamoja/native';
18
+ export type { SealedMessage };
19
+ /**
20
+ * Which side of a session a device is on.
21
+ *
22
+ * The two devices must choose opposite roles: the role decides the order the
23
+ * public keys are mixed in and which direction each side tags its messages
24
+ * with, so a session where both sides claim the same role opens nothing.
25
+ *
26
+ * Provided as a runtime object plus a matching string-union type.
27
+ */
28
+ export declare const Role: {
29
+ /** The device that opens the session. */
30
+ readonly Initiator: RoleName;
31
+ /** The device that answers. */
32
+ readonly Responder: RoleName;
33
+ };
34
+ /** One of the {@link Role} choices. */
35
+ export type Role = RoleName;
36
+ /** A confidential, tamper-evident, replay-protected channel with one peer. */
37
+ export declare class Session {
38
+ #private;
39
+ /**
40
+ * Establishes a session with a peer.
41
+ *
42
+ * @param local - This device's key-agreement secret.
43
+ * @param peerPublicKey - The peer's 32-byte public key, already authenticated
44
+ * by pinning or by a signature.
45
+ * @param salt - A fresh per-session salt both sides share, exchanged in the
46
+ * clear. Reusing one with the same pair of keys reuses the session key, so
47
+ * it must change each session.
48
+ * @param role - Whether this device opens the session or answers.
49
+ */
50
+ constructor(local: NativeAgreementKey, peerPublicKey: Buffer, salt: Buffer, role: Role);
51
+ /**
52
+ * Seals a message for the peer.
53
+ *
54
+ * @param plaintext - The message to protect.
55
+ * @param aad - Data authenticated but not encrypted, so it stays readable on
56
+ * the wire yet cannot be altered: a device identifier or a routing header
57
+ * belongs here.
58
+ * @returns The ciphertext, with the counter and tag to send beside it.
59
+ */
60
+ seal(plaintext: Buffer, aad?: Buffer): SealedMessage;
61
+ /**
62
+ * Opens a message from the peer.
63
+ *
64
+ * @param sealed - The ciphertext with the counter and tag that arrived with
65
+ * it.
66
+ * @param aad - The same associated data the sender authenticated.
67
+ * @returns The plaintext.
68
+ * @throws When the counter repeats or is older than the replay window still
69
+ * tracks, and when the tag does not authenticate. Nothing readable is ever
70
+ * returned from a message that failed either check.
71
+ */
72
+ open(sealed: SealedMessage, aad?: Buffer): Buffer;
73
+ }
74
+ /**
75
+ * Computes a keyed hash over a message.
76
+ *
77
+ * This is the primitive a host uses to authenticate a pairing exchange or a
78
+ * single command, where a whole session would be more than the job needs.
79
+ */
80
+ export declare function hmacSha256(key: Buffer, message: Buffer): Buffer;
81
+ /** Expands input keying material into `length` bytes bound to `info`. */
82
+ export declare function hkdfSha256(salt: Buffer, ikm: Buffer, info: Buffer, length: number): Buffer;
package/dist/index.js ADDED
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ /**
3
+ * Ergonomic facade over the generated session binding.
4
+ *
5
+ * Two devices that already know each other's public keys can agree on a session
6
+ * key without ever sending it, and then exchange messages that are confidential,
7
+ * cannot be altered undetected, and cannot be replayed. That is the whole of
8
+ * what a small device usually needs from transport security, at a fraction of
9
+ * what a TLS stack costs it.
10
+ *
11
+ * The role is re-exported as a runtime {@link Role} object, because the
12
+ * generated enum is types-only.
13
+ *
14
+ * @packageDocumentation
15
+ */
16
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
17
+ if (kind === "m") throw new TypeError("Private method is not writable");
18
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
19
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
20
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
21
+ };
22
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
23
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
24
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
25
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
26
+ };
27
+ var _Session_inner;
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.Session = exports.Role = exports.AgreementKey = void 0;
30
+ exports.hmacSha256 = hmacSha256;
31
+ exports.hkdfSha256 = hkdfSha256;
32
+ const native_1 = require("@pamoja/native");
33
+ var native_2 = require("@pamoja/native");
34
+ Object.defineProperty(exports, "AgreementKey", { enumerable: true, get: function () { return native_2.AgreementKey; } });
35
+ /**
36
+ * Which side of a session a device is on.
37
+ *
38
+ * The two devices must choose opposite roles: the role decides the order the
39
+ * public keys are mixed in and which direction each side tags its messages
40
+ * with, so a session where both sides claim the same role opens nothing.
41
+ *
42
+ * Provided as a runtime object plus a matching string-union type.
43
+ */
44
+ exports.Role = {
45
+ /** The device that opens the session. */
46
+ Initiator: 'Initiator',
47
+ /** The device that answers. */
48
+ Responder: 'Responder',
49
+ };
50
+ /** A confidential, tamper-evident, replay-protected channel with one peer. */
51
+ class Session {
52
+ /**
53
+ * Establishes a session with a peer.
54
+ *
55
+ * @param local - This device's key-agreement secret.
56
+ * @param peerPublicKey - The peer's 32-byte public key, already authenticated
57
+ * by pinning or by a signature.
58
+ * @param salt - A fresh per-session salt both sides share, exchanged in the
59
+ * clear. Reusing one with the same pair of keys reuses the session key, so
60
+ * it must change each session.
61
+ * @param role - Whether this device opens the session or answers.
62
+ */
63
+ constructor(local, peerPublicKey, salt, role) {
64
+ _Session_inner.set(this, void 0);
65
+ __classPrivateFieldSet(this, _Session_inner, new native_1.Session(local, peerPublicKey, salt, role), "f");
66
+ }
67
+ /**
68
+ * Seals a message for the peer.
69
+ *
70
+ * @param plaintext - The message to protect.
71
+ * @param aad - Data authenticated but not encrypted, so it stays readable on
72
+ * the wire yet cannot be altered: a device identifier or a routing header
73
+ * belongs here.
74
+ * @returns The ciphertext, with the counter and tag to send beside it.
75
+ */
76
+ seal(plaintext, aad) {
77
+ return __classPrivateFieldGet(this, _Session_inner, "f").seal(plaintext, aad);
78
+ }
79
+ /**
80
+ * Opens a message from the peer.
81
+ *
82
+ * @param sealed - The ciphertext with the counter and tag that arrived with
83
+ * it.
84
+ * @param aad - The same associated data the sender authenticated.
85
+ * @returns The plaintext.
86
+ * @throws When the counter repeats or is older than the replay window still
87
+ * tracks, and when the tag does not authenticate. Nothing readable is ever
88
+ * returned from a message that failed either check.
89
+ */
90
+ open(sealed, aad) {
91
+ return __classPrivateFieldGet(this, _Session_inner, "f").open(sealed, aad);
92
+ }
93
+ }
94
+ exports.Session = Session;
95
+ _Session_inner = new WeakMap();
96
+ /**
97
+ * Computes a keyed hash over a message.
98
+ *
99
+ * This is the primitive a host uses to authenticate a pairing exchange or a
100
+ * single command, where a whole session would be more than the job needs.
101
+ */
102
+ function hmacSha256(key, message) {
103
+ return (0, native_1.hmacSha256Digest)(key, message);
104
+ }
105
+ /** Expands input keying material into `length` bytes bound to `info`. */
106
+ function hkdfSha256(salt, ikm, info, length) {
107
+ return (0, native_1.hkdfSha256Expand)(salt, ikm, info, length);
108
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pamoja/session",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "X25519 key agreement, HKDF, and ChaCha20-Poly1305 with an anti-replay window, with no TLS stack.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -34,6 +34,6 @@
34
34
  "node": ">= 16"
35
35
  },
36
36
  "dependencies": {
37
- "@pamoja/native": "0.1.15"
37
+ "@pamoja/native": "0.1.16"
38
38
  }
39
39
  }