@sideband/secure-relay 0.2.1 → 0.2.2

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
@@ -12,7 +12,7 @@ Implements authenticated handshake, key derivation, and message encryption for s
12
12
  - **TOFU identity pinning** — Trust-on-first-use with key change detection
13
13
  - **Replay protection** — Bitmap-based sequence window
14
14
 
15
- ## Non-Goals
15
+ ## Non-goals
16
16
 
17
17
  This package intentionally does NOT:
18
18
 
@@ -21,6 +21,23 @@ This package intentionally does NOT:
21
21
  - Persist identity keys or TOFU pins
22
22
  - Implement relay authentication or tokens
23
23
 
24
+ ## Threat model
25
+
26
+ This package protects the **payload** of messages between a browser client and a daemon via an untrusted relay. Specifically:
27
+
28
+ - The relay cannot read or tamper with message content (authenticated encryption).
29
+ - A MITM cannot impersonate the daemon without its Ed25519 private key (signature verification on handshake).
30
+ - Replayed messages are rejected within the sequence window.
31
+
32
+ It does **not** protect against:
33
+
34
+ - Compromise of the daemon's identity key (store it securely; if lost, all clients see a TOFU mismatch).
35
+ - Traffic analysis (message sizes and timing are visible to the relay).
36
+ - Key storage security — this package has no opinion on where keys live; that's the caller's responsibility.
37
+ - Denial of service from a malicious relay (the relay can drop or delay messages).
38
+
39
+ This implementation has not undergone a formal third-party security audit. Use accordingly.
40
+
24
41
  ## Install
25
42
 
26
43
  ```bash
@@ -78,7 +95,7 @@ const encrypted = encryptClientToDaemon(daemonSession, plaintext);
78
95
  const decrypted = decryptClientToDaemon(clientSession, encrypted);
79
96
  ```
80
97
 
81
- ## TOFU Security
98
+ ## TOFU security
82
99
 
83
100
  Identity keys use trust-on-first-use (TOFU) pinning:
84
101
 
@@ -86,7 +103,7 @@ Identity keys use trust-on-first-use (TOFU) pinning:
86
103
  - Never accept key changes silently — `identity_key_changed` indicates potential MITM
87
104
  - On mismatch, present both fingerprints and require explicit user approval
88
105
 
89
- ### Detecting Identity Key Changes
106
+ ### Detecting identity key changes
90
107
 
91
108
  Compare the daemon's current identity key against your stored pin before handshake:
92
109
 
@@ -123,7 +140,7 @@ if (!pinnedKey) {
123
140
  }
124
141
  ```
125
142
 
126
- ## Error Handling
143
+ ## Error handling
127
144
 
128
145
  All errors throw `SbrpError` with a specific `code`:
129
146
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sideband/secure-relay",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Secure Relay Protocol (SBRP): E2EE handshake, session encryption, and TOFU identity pinning for relay-mediated communication.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -45,9 +45,9 @@
45
45
  "./package.json": "./package.json"
46
46
  },
47
47
  "dependencies": {
48
- "@noble/ciphers": "^1.2.1",
49
- "@noble/curves": "^1.8.1",
50
- "@noble/hashes": "^1.7.1"
48
+ "@noble/ciphers": "^2.1.1",
49
+ "@noble/curves": "^2.0.1",
50
+ "@noble/hashes": "^2.0.1"
51
51
  },
52
52
  "files": [
53
53
  "dist",
package/src/crypto.ts CHANGED
@@ -7,12 +7,12 @@
7
7
  * and @noble/hashes for SHA-256/HKDF.
8
8
  */
9
9
 
10
- import { chacha20poly1305 } from "@noble/ciphers/chacha";
11
- import { ed25519 } from "@noble/curves/ed25519";
12
- import { x25519 } from "@noble/curves/ed25519";
13
- import { hkdf } from "@noble/hashes/hkdf";
14
- import { sha256 } from "@noble/hashes/sha256";
15
- import { concatBytes, randomBytes } from "@noble/hashes/utils";
10
+ import { chacha20poly1305 } from "@noble/ciphers/chacha.js";
11
+ import { ed25519 } from "@noble/curves/ed25519.js";
12
+ import { x25519 } from "@noble/curves/ed25519.js";
13
+ import { hkdf } from "@noble/hashes/hkdf.js";
14
+ import { sha256 } from "@noble/hashes/sha2.js";
15
+ import { concatBytes, randomBytes } from "@noble/hashes/utils.js";
16
16
  import {
17
17
  AUTH_TAG_LENGTH,
18
18
  DIRECTION_CLIENT_TO_DAEMON,
@@ -36,14 +36,14 @@ const textEncoder = new TextEncoder();
36
36
 
37
37
  /** Generate a new Ed25519 identity keypair */
38
38
  export function generateIdentityKeyPair(): IdentityKeyPair {
39
- const privateKey = ed25519.utils.randomPrivateKey();
39
+ const privateKey = ed25519.utils.randomSecretKey();
40
40
  const publicKey = ed25519.getPublicKey(privateKey);
41
41
  return { publicKey, privateKey };
42
42
  }
43
43
 
44
44
  /** Generate a new X25519 ephemeral keypair */
45
45
  export function generateEphemeralKeyPair(): EphemeralKeyPair {
46
- const privateKey = x25519.utils.randomPrivateKey();
46
+ const privateKey = x25519.utils.randomSecretKey();
47
47
  const publicKey = x25519.getPublicKey(privateKey);
48
48
  return { publicKey, privateKey };
49
49
  }
@@ -137,7 +137,7 @@ export function deriveSessionKeys(
137
137
  sha256,
138
138
  sharedSecret,
139
139
  transcriptHash,
140
- SBRP_SESSION_KEYS_INFO,
140
+ textEncoder.encode(SBRP_SESSION_KEYS_INFO),
141
141
  SESSION_KEYS_LENGTH,
142
142
  );
143
143