@sideband/secure-relay 0.1.0 → 0.2.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.
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # @sideband/secure-relay
2
2
 
3
- End-to-end encrypted communication between browsers and daemons via untrusted relay servers.
3
+ Low-level E2EE primitives for the Sideband Relay Protocol (SBRP).
4
+
5
+ Implements authenticated handshake, key derivation, and message encryption for secure browser ↔ daemon communication via untrusted relay servers. Most applications should use `@sideband/peer` instead of this package directly.
4
6
 
5
7
  ## Features
6
8
 
@@ -10,6 +12,15 @@ End-to-end encrypted communication between browsers and daemons via untrusted re
10
12
  - **TOFU identity pinning** — Trust-on-first-use with key change detection
11
13
  - **Replay protection** — Bitmap-based sequence window
12
14
 
15
+ ## Non-Goals
16
+
17
+ This package intentionally does NOT:
18
+
19
+ - Handle network transport or WebSockets
20
+ - Manage session lifecycle or reconnection
21
+ - Persist identity keys or TOFU pins
22
+ - Implement relay authentication or tokens
23
+
13
24
  ## Install
14
25
 
15
26
  ```bash
@@ -18,7 +29,7 @@ bun add @sideband/secure-relay
18
29
 
19
30
  ## Usage
20
31
 
21
- ```typescript
32
+ ```ts
22
33
  import {
23
34
  generateIdentityKeyPair,
24
35
  createHandshakeInit,
@@ -34,7 +45,8 @@ import {
34
45
  asClientId,
35
46
  } from "@sideband/secure-relay";
36
47
 
37
- // Daemon: generate identity keypair (persist this!)
48
+ // Daemon: generate identity keypair ONCE and persist securely.
49
+ // Regenerating causes TOFU mismatch warnings for all clients.
38
50
  const identity = generateIdentityKeyPair();
39
51
  const daemonId = asDaemonId("my-daemon");
40
52
 
@@ -61,25 +73,72 @@ const { sessionKeys } = processHandshakeAccept(
61
73
  );
62
74
  const daemonSession = createDaemonSession(sessionKeys);
63
75
 
64
- // Encrypt/decrypt messages
76
+ // Encrypt/decrypt messages (sessions are stateful — do not clone)
65
77
  const encrypted = encryptClientToDaemon(daemonSession, plaintext);
66
78
  const decrypted = decryptClientToDaemon(clientSession, encrypted);
67
79
  ```
68
80
 
81
+ ## TOFU Security
82
+
83
+ Identity keys use trust-on-first-use (TOFU) pinning:
84
+
85
+ - Pin daemon identity keys on first successful handshake
86
+ - Never accept key changes silently — `identity_key_changed` indicates potential MITM
87
+ - On mismatch, present both fingerprints and require explicit user approval
88
+
89
+ ### Detecting Identity Key Changes
90
+
91
+ Compare the daemon's current identity key against your stored pin before handshake:
92
+
93
+ ```ts
94
+ import {
95
+ processHandshakeAccept,
96
+ computeFingerprint,
97
+ SbrpError,
98
+ SbrpErrorCode,
99
+ } from "@sideband/secure-relay";
100
+
101
+ // Load pinned key from storage (null on first connection)
102
+ const pinnedKey = await storage.get(`tofu:${daemonId}`);
103
+
104
+ if (pinnedKey && !equalBytes(pinnedKey, currentIdentityKey)) {
105
+ // Key changed — potential MITM attack
106
+ throw new SbrpError(
107
+ SbrpErrorCode.IdentityKeyChanged,
108
+ `Identity key changed for ${daemonId}. ` +
109
+ `Expected: ${computeFingerprint(pinnedKey)}, ` +
110
+ `Got: ${computeFingerprint(currentIdentityKey)}`,
111
+ );
112
+ }
113
+
114
+ // First connection: pin the key after successful handshake
115
+ const result = processHandshakeAccept(
116
+ accept,
117
+ daemonId,
118
+ currentIdentityKey,
119
+ ephemeralKeyPair,
120
+ );
121
+ if (!pinnedKey) {
122
+ await storage.set(`tofu:${daemonId}`, currentIdentityKey);
123
+ }
124
+ ```
125
+
69
126
  ## Error Handling
70
127
 
71
128
  All errors throw `SbrpError` with a specific `code`:
72
129
 
73
- | Code | Meaning |
74
- | ---------------------- | ----------------------------------------- |
75
- | `identity_key_changed` | Pinned key doesn't match (potential MITM) |
76
- | `handshake_failed` | Signature verification failed |
77
- | `decrypt_failed` | Message authentication failed |
78
- | `sequence_error` | Replay detected or sequence out of window |
130
+ | Code | Meaning | Recovery |
131
+ | ---------------------- | ----------------------------------------- | ------------------------- |
132
+ | `identity_key_changed` | Pinned key doesn't match (potential MITM) | Close session, alert user |
133
+ | `handshake_failed` | Signature verification failed | Close session |
134
+ | `decrypt_failed` | Message authentication failed | Close session |
135
+ | `sequence_error` | Replay detected or sequence out of window | Close session |
136
+
137
+ All errors are fatal — close the session and re-handshake.
79
138
 
80
139
  ## Specification
81
140
 
82
- See [Secure Relay Protocol](https://sideband.tech/specs/secure-relay-protocol) for the full protocol specification.
141
+ See the [SBRP protocol specification](https://sideband.tech/protocols/sbrp/) for implementation details.
83
142
 
84
143
  ## License
85
144