@agora-sdk/secure-chat-crypto 0.4.0 → 0.5.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.
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interface.d.ts +77 -1
- package/dist/cjs/interface.js +19 -0
- package/dist/cjs/interface.js.map +1 -1
- package/dist/cjs/mock-crypto.d.ts +4 -3
- package/dist/cjs/mock-crypto.js +54 -9
- package/dist/cjs/mock-crypto.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interface.d.ts +77 -1
- package/dist/esm/interface.js +17 -1
- package/dist/esm/interface.js.map +1 -1
- package/dist/esm/mock-crypto.d.ts +4 -3
- package/dist/esm/mock-crypto.js +54 -9
- package/dist/esm/mock-crypto.js.map +1 -1
- package/dist/esm/ts-mls/backup.d.ts +30 -0
- package/dist/esm/ts-mls/backup.js +105 -0
- package/dist/esm/ts-mls/backup.js.map +1 -0
- package/dist/esm/ts-mls/crypto.d.ts +24 -3
- package/dist/esm/ts-mls/crypto.js +96 -17
- package/dist/esm/ts-mls/crypto.js.map +1 -1
- package/package.json +1 -1
package/dist/esm/mock-crypto.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SecureChatDecryptError } from "./interface.js";
|
|
1
2
|
const enc = new TextEncoder();
|
|
2
3
|
const dec = new TextDecoder();
|
|
3
4
|
const BACKUP_MAGIC = "AGORA_MOCK_BACKUP_V1";
|
|
@@ -75,13 +76,15 @@ export class MockSecureChatCrypto {
|
|
|
75
76
|
bytesFrom(`grp:${did}:${opts.initialMembers.map((m) => m.deviceId).join(",")}`, 16);
|
|
76
77
|
const idHex = toHex(mlsGroupId);
|
|
77
78
|
const secret = bytesFrom(`secret:${idHex}:${did}`, 32);
|
|
78
|
-
|
|
79
|
+
const members = [did, ...opts.initialMembers.map((m) => m.deviceId)];
|
|
80
|
+
this.groups.set(idHex, { secret, epoch: 0n, members });
|
|
79
81
|
const welcomes = opts.initialMembers.map((m) => ({
|
|
80
82
|
targetDeviceId: m.deviceId,
|
|
81
83
|
payload: jsonBytes({
|
|
82
84
|
groupId: idHex,
|
|
83
85
|
secret: toHex(secret),
|
|
84
86
|
epoch: "0",
|
|
87
|
+
members,
|
|
85
88
|
}),
|
|
86
89
|
}));
|
|
87
90
|
return { group: { mlsGroupId, epoch: 0n }, welcomes };
|
|
@@ -93,6 +96,8 @@ export class MockSecureChatCrypto {
|
|
|
93
96
|
throw new Error("mock: unknown group");
|
|
94
97
|
st.epoch += 1n;
|
|
95
98
|
const epoch = st.epoch;
|
|
99
|
+
if (!st.members.includes(newDevice.deviceId))
|
|
100
|
+
st.members.push(newDevice.deviceId);
|
|
96
101
|
return {
|
|
97
102
|
commit: jsonBytes({ type: "commit", groupId: idHex, epoch: epoch.toString() }),
|
|
98
103
|
welcomes: [
|
|
@@ -102,18 +107,20 @@ export class MockSecureChatCrypto {
|
|
|
102
107
|
groupId: idHex,
|
|
103
108
|
secret: toHex(st.secret),
|
|
104
109
|
epoch: epoch.toString(),
|
|
110
|
+
members: st.members,
|
|
105
111
|
}),
|
|
106
112
|
},
|
|
107
113
|
],
|
|
108
114
|
epoch,
|
|
109
115
|
};
|
|
110
116
|
}
|
|
111
|
-
async removeMember(group,
|
|
117
|
+
async removeMember(group, leafDeviceId) {
|
|
112
118
|
const idHex = toHex(group.mlsGroupId);
|
|
113
119
|
const st = this.groups.get(idHex);
|
|
114
120
|
if (!st)
|
|
115
121
|
throw new Error("mock: unknown group");
|
|
116
122
|
st.epoch += 1n;
|
|
123
|
+
st.members = st.members.filter((m) => m !== leafDeviceId);
|
|
117
124
|
return {
|
|
118
125
|
commit: jsonBytes({ type: "commit", groupId: idHex, epoch: st.epoch.toString() }),
|
|
119
126
|
welcomes: [],
|
|
@@ -138,7 +145,7 @@ export class MockSecureChatCrypto {
|
|
|
138
145
|
const idHex = toHex(group.mlsGroupId);
|
|
139
146
|
const st = this.groups.get(idHex);
|
|
140
147
|
if (!st)
|
|
141
|
-
throw new
|
|
148
|
+
throw new SecureChatDecryptError("unknown", "mock: unknown group");
|
|
142
149
|
// header = "<deviceId>|<epoch>|" — split on the SECOND pipe.
|
|
143
150
|
let pipes = 0;
|
|
144
151
|
let cut = -1;
|
|
@@ -152,7 +159,7 @@ export class MockSecureChatCrypto {
|
|
|
152
159
|
}
|
|
153
160
|
}
|
|
154
161
|
if (cut < 0)
|
|
155
|
-
throw new
|
|
162
|
+
throw new SecureChatDecryptError("malformed", "mock: malformed ciphertext");
|
|
156
163
|
const [senderDeviceId, epochStr] = dec.decode(ciphertext.slice(0, cut - 1)).split("|");
|
|
157
164
|
const body = ciphertext.slice(cut);
|
|
158
165
|
const ks = keystream(st.secret, body.length);
|
|
@@ -164,9 +171,25 @@ export class MockSecureChatCrypto {
|
|
|
164
171
|
}
|
|
165
172
|
async processWelcome(welcome) {
|
|
166
173
|
const w = parseJson(welcome);
|
|
167
|
-
this.groups.set(w.groupId, {
|
|
174
|
+
this.groups.set(w.groupId, {
|
|
175
|
+
secret: fromHex(w.secret),
|
|
176
|
+
epoch: BigInt(w.epoch),
|
|
177
|
+
members: w.members ?? [],
|
|
178
|
+
});
|
|
168
179
|
return { mlsGroupId: fromHex(w.groupId), epoch: BigInt(w.epoch) };
|
|
169
180
|
}
|
|
181
|
+
async exportGroupIdentities(group) {
|
|
182
|
+
const idHex = toHex(group.mlsGroupId);
|
|
183
|
+
const st = this.groups.get(idHex);
|
|
184
|
+
if (!st)
|
|
185
|
+
throw new Error("mock: unknown group");
|
|
186
|
+
// The mock derives each device's signature key deterministically from its id (see
|
|
187
|
+
// generateDeviceIdentity), so the roster of device ids is enough to reconstruct every member's key.
|
|
188
|
+
return st.members.map((deviceId) => ({
|
|
189
|
+
deviceId,
|
|
190
|
+
signaturePublicKey: bytesFrom(`sig:${deviceId}`, 32),
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
170
193
|
async processCommit(group, commit) {
|
|
171
194
|
const c = parseJson(commit);
|
|
172
195
|
const idHex = toHex(group.mlsGroupId);
|
|
@@ -207,11 +230,20 @@ export class MockSecureChatCrypto {
|
|
|
207
230
|
const st = this.groups.get(idHex);
|
|
208
231
|
if (!st)
|
|
209
232
|
throw new Error("mock: unknown group");
|
|
210
|
-
return jsonBytes({
|
|
233
|
+
return jsonBytes({
|
|
234
|
+
groupId: idHex,
|
|
235
|
+
secret: toHex(st.secret),
|
|
236
|
+
epoch: st.epoch.toString(),
|
|
237
|
+
members: st.members,
|
|
238
|
+
});
|
|
211
239
|
}
|
|
212
240
|
async importGroupState(state) {
|
|
213
241
|
const s = parseJson(state);
|
|
214
|
-
this.groups.set(s.groupId, {
|
|
242
|
+
this.groups.set(s.groupId, {
|
|
243
|
+
secret: fromHex(s.secret),
|
|
244
|
+
epoch: BigInt(s.epoch),
|
|
245
|
+
members: s.members ?? [],
|
|
246
|
+
});
|
|
215
247
|
return { mlsGroupId: fromHex(s.groupId), epoch: BigInt(s.epoch) };
|
|
216
248
|
}
|
|
217
249
|
async exportBackup(passphrase) {
|
|
@@ -219,11 +251,13 @@ export class MockSecureChatCrypto {
|
|
|
219
251
|
id,
|
|
220
252
|
secret: toHex(st.secret),
|
|
221
253
|
epoch: st.epoch.toString(),
|
|
254
|
+
members: st.members,
|
|
222
255
|
}));
|
|
223
256
|
const plain = jsonBytes({
|
|
224
257
|
magic: BACKUP_MAGIC,
|
|
225
258
|
identityPriv: this.privateState ? toHex(this.privateState) : null,
|
|
226
259
|
deviceId: this.identity?.deviceId ?? null,
|
|
260
|
+
ciphersuite: this.identity?.ciphersuite ?? 1,
|
|
227
261
|
groups,
|
|
228
262
|
});
|
|
229
263
|
const salt = bytesFrom(`salt:${passphrase}`, 16);
|
|
@@ -248,14 +282,25 @@ export class MockSecureChatCrypto {
|
|
|
248
282
|
catch {
|
|
249
283
|
throw new Error("mock: backup decrypt failed (wrong passphrase?)");
|
|
250
284
|
}
|
|
251
|
-
if (parsed.magic !== BACKUP_MAGIC) {
|
|
285
|
+
if (parsed.magic !== BACKUP_MAGIC || !parsed.deviceId) {
|
|
252
286
|
throw new Error("mock: backup decrypt failed (wrong passphrase?)");
|
|
253
287
|
}
|
|
254
288
|
if (parsed.identityPriv)
|
|
255
289
|
this.privateState = fromHex(parsed.identityPriv);
|
|
256
290
|
for (const g of parsed.groups) {
|
|
257
|
-
this.groups.set(g.id, { secret: fromHex(g.secret), epoch: BigInt(g.epoch) });
|
|
291
|
+
this.groups.set(g.id, { secret: fromHex(g.secret), epoch: BigInt(g.epoch), members: g.members ?? [] });
|
|
258
292
|
}
|
|
293
|
+
// Rebuild the (deterministic) identity so the restored mock is usable, and return it — symmetric
|
|
294
|
+
// with importDeviceState, so the restore flow can re-assert the device server-side.
|
|
295
|
+
const ciphersuite = parsed.ciphersuite ?? 1;
|
|
296
|
+
const identity = {
|
|
297
|
+
deviceId: parsed.deviceId,
|
|
298
|
+
signaturePublicKey: bytesFrom(`sig:${parsed.deviceId}`, 32),
|
|
299
|
+
credential: enc.encode(parsed.deviceId),
|
|
300
|
+
ciphersuite,
|
|
301
|
+
};
|
|
302
|
+
this.identity = identity;
|
|
303
|
+
return identity;
|
|
259
304
|
}
|
|
260
305
|
}
|
|
261
306
|
//# sourceMappingURL=mock-crypto.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-crypto.js","sourceRoot":"","sources":["../../src/mock-crypto.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mock-crypto.js","sourceRoot":"","sources":["../../src/mock-crypto.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PassphraseBackup } from "../interface.js";
|
|
2
|
+
/**
|
|
3
|
+
* argon2id parameters — RFC 9106 "FIRST RECOMMENDED" high-memory profile (m=64 MiB, t=3, p=1),
|
|
4
|
+
* 32-byte derived key. Backup/restore is rare, so the ~0.5–1s cost is acceptable and buys strong
|
|
5
|
+
* resistance to offline brute-force of the passphrase if the server's blob store is exfiltrated.
|
|
6
|
+
*/
|
|
7
|
+
export declare const ARGON2_PARAMS: {
|
|
8
|
+
readonly m: 65536;
|
|
9
|
+
readonly t: 3;
|
|
10
|
+
readonly p: 1;
|
|
11
|
+
readonly dkLen: 32;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Seal plaintext key material into a passphrase-encrypted {@link PassphraseBackup}.
|
|
15
|
+
*
|
|
16
|
+
* @param plaintext - The serialized key material to protect.
|
|
17
|
+
* @param passphrase - The user's backup passphrase.
|
|
18
|
+
* @returns The encrypted envelope (random salt in `kdfParams`, random `nonce`, argon2id + xchacha20poly1305).
|
|
19
|
+
*/
|
|
20
|
+
export declare function sealBackup(plaintext: Uint8Array, passphrase: string): Promise<PassphraseBackup>;
|
|
21
|
+
/**
|
|
22
|
+
* Open a {@link PassphraseBackup} sealed by {@link sealBackup}.
|
|
23
|
+
*
|
|
24
|
+
* @param backup - The encrypted envelope.
|
|
25
|
+
* @param passphrase - The user's backup passphrase.
|
|
26
|
+
* @returns The decrypted plaintext key material.
|
|
27
|
+
* @throws {Error} On an unknown `kdf`/`cipher`/`version`, a missing salt, or AEAD authentication
|
|
28
|
+
* failure (wrong passphrase, or a tampered blob/nonce/metadata) — always fails closed.
|
|
29
|
+
*/
|
|
30
|
+
export declare function openBackup(backup: PassphraseBackup, passphrase: string): Promise<Uint8Array>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Passphrase backup envelope codec — the REAL at-rest crypto for key-material backups.
|
|
2
|
+
//
|
|
3
|
+
// Where it sits in the blind-server model: the Agora server stores the resulting `blob` verbatim and
|
|
4
|
+
// can never decrypt it (it never sees the passphrase; the KDF params alone are useless). So this is
|
|
5
|
+
// the one place the backup's secrecy is decided. Per CLAUDE.md #1 we use a real memory-hard KDF
|
|
6
|
+
// (argon2id, RFC 9106 high-memory profile) so a weak passphrase is expensive to brute-force on a DB
|
|
7
|
+
// exfil, and an AEAD (xchacha20poly1305) so a tampered blob/nonce/metadata fails closed.
|
|
8
|
+
//
|
|
9
|
+
// Binary is `Uint8Array` in memory; the wire/transport layer base64-encodes `blob`/`nonce` and the
|
|
10
|
+
// KDF params (incl. the hex salt) are non-secret metadata stored alongside.
|
|
11
|
+
import { argon2idAsync } from "@noble/hashes/argon2.js";
|
|
12
|
+
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
|
|
13
|
+
import { zeroOutUint8Array } from "ts-mls";
|
|
14
|
+
import { toHex, fromHex } from "./hex.js";
|
|
15
|
+
const utf8 = (s) => new TextEncoder().encode(s);
|
|
16
|
+
/** The only KDF this codec emits/accepts. */
|
|
17
|
+
const KDF = "argon2id";
|
|
18
|
+
/** The only AEAD this codec emits/accepts. */
|
|
19
|
+
const CIPHER = "xchacha20poly1305";
|
|
20
|
+
/** The only envelope version this codec emits/accepts. */
|
|
21
|
+
const VERSION = 1;
|
|
22
|
+
const SALT_BYTES = 16;
|
|
23
|
+
const NONCE_BYTES = 24; // xchacha20poly1305 extended nonce — safe with random nonces
|
|
24
|
+
/**
|
|
25
|
+
* argon2id parameters — RFC 9106 "FIRST RECOMMENDED" high-memory profile (m=64 MiB, t=3, p=1),
|
|
26
|
+
* 32-byte derived key. Backup/restore is rare, so the ~0.5–1s cost is acceptable and buys strong
|
|
27
|
+
* resistance to offline brute-force of the passphrase if the server's blob store is exfiltrated.
|
|
28
|
+
*/
|
|
29
|
+
export const ARGON2_PARAMS = { m: 65536, t: 3, p: 1, dkLen: 32 };
|
|
30
|
+
/**
|
|
31
|
+
* The associated data bound into the AEAD: the STABLE scalar envelope descriptors. Binding them means
|
|
32
|
+
* an attacker can't swap the stored `kdf`/`cipher`/`version` (e.g. downgrade the KDF) without the open
|
|
33
|
+
* failing closed.
|
|
34
|
+
*
|
|
35
|
+
* `kdfParams` is deliberately NOT bound here: the server stores it as Postgres jsonb, which does not
|
|
36
|
+
* preserve object key order, so a `JSON.stringify(kdfParams)`-based AAD would differ between seal and
|
|
37
|
+
* open and break a perfectly valid backup. It needs no AAD anyway — the `salt` is bound implicitly
|
|
38
|
+
* (it's a KDF input: any change yields the wrong key and the AEAD fails), and the cost params are
|
|
39
|
+
* pinned to {@link ARGON2_PARAMS} on open, so tampering them is inert.
|
|
40
|
+
*/
|
|
41
|
+
function aad(kdf, cipher, version) {
|
|
42
|
+
return utf8(JSON.stringify({ v: version, kdf, cipher }));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Derive a 32-byte key from the passphrase + salt with argon2id at {@link ARGON2_PARAMS}.
|
|
46
|
+
*
|
|
47
|
+
* @param passphrase - The user's backup passphrase.
|
|
48
|
+
* @param salt - The 16-byte random salt.
|
|
49
|
+
* @returns The 32-byte derived symmetric key (caller must zeroize after use).
|
|
50
|
+
*/
|
|
51
|
+
async function deriveKey(passphrase, salt) {
|
|
52
|
+
return argon2idAsync(utf8(passphrase), salt, ARGON2_PARAMS);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Seal plaintext key material into a passphrase-encrypted {@link PassphraseBackup}.
|
|
56
|
+
*
|
|
57
|
+
* @param plaintext - The serialized key material to protect.
|
|
58
|
+
* @param passphrase - The user's backup passphrase.
|
|
59
|
+
* @returns The encrypted envelope (random salt in `kdfParams`, random `nonce`, argon2id + xchacha20poly1305).
|
|
60
|
+
*/
|
|
61
|
+
export async function sealBackup(plaintext, passphrase) {
|
|
62
|
+
const salt = crypto.getRandomValues(new Uint8Array(SALT_BYTES));
|
|
63
|
+
const nonce = crypto.getRandomValues(new Uint8Array(NONCE_BYTES));
|
|
64
|
+
const kdfParams = { salt: toHex(salt), m: ARGON2_PARAMS.m, t: ARGON2_PARAMS.t, p: ARGON2_PARAMS.p };
|
|
65
|
+
const key = await deriveKey(passphrase, salt);
|
|
66
|
+
try {
|
|
67
|
+
const blob = xchacha20poly1305(key, nonce, aad(KDF, CIPHER, VERSION)).encrypt(plaintext);
|
|
68
|
+
return { blob, kdf: KDF, kdfParams, cipher: CIPHER, nonce, version: VERSION };
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
zeroOutUint8Array(key);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Open a {@link PassphraseBackup} sealed by {@link sealBackup}.
|
|
76
|
+
*
|
|
77
|
+
* @param backup - The encrypted envelope.
|
|
78
|
+
* @param passphrase - The user's backup passphrase.
|
|
79
|
+
* @returns The decrypted plaintext key material.
|
|
80
|
+
* @throws {Error} On an unknown `kdf`/`cipher`/`version`, a missing salt, or AEAD authentication
|
|
81
|
+
* failure (wrong passphrase, or a tampered blob/nonce/metadata) — always fails closed.
|
|
82
|
+
*/
|
|
83
|
+
export async function openBackup(backup, passphrase) {
|
|
84
|
+
if (backup.kdf !== KDF)
|
|
85
|
+
throw new Error(`secure-chat: unsupported backup kdf "${backup.kdf}"`);
|
|
86
|
+
if (backup.cipher !== CIPHER)
|
|
87
|
+
throw new Error(`secure-chat: unsupported backup cipher "${backup.cipher}"`);
|
|
88
|
+
if (backup.version !== VERSION)
|
|
89
|
+
throw new Error(`secure-chat: unsupported backup version ${backup.version}`);
|
|
90
|
+
const saltHex = backup.kdfParams.salt;
|
|
91
|
+
if (!saltHex)
|
|
92
|
+
throw new Error("secure-chat: backup is missing its KDF salt");
|
|
93
|
+
const key = await deriveKey(passphrase, fromHex(saltHex));
|
|
94
|
+
try {
|
|
95
|
+
return xchacha20poly1305(key, backup.nonce, aad(backup.kdf, backup.cipher, backup.version)).decrypt(backup.blob);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Don't leak which check failed; a wrong passphrase and a tampered blob are indistinguishable here.
|
|
99
|
+
throw new Error("secure-chat: backup decrypt failed (wrong passphrase or corrupt backup)");
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
zeroOutUint8Array(key);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=backup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backup.js","sourceRoot":"","sources":["../../../src/ts-mls/backup.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CiphersuiteImpl, type KeyPackage, type PrivateKeyPackage, type ClientState } from "ts-mls";
|
|
2
|
-
import type { SecureChatCrypto, DeviceIdentity, KeyPackageBundle, GroupHandle, CommitResult, TargetedWelcome, PassphraseBackup } from "../interface.js";
|
|
2
|
+
import type { SecureChatCrypto, DeviceIdentity, KeyPackageBundle, GroupHandle, GroupMemberIdentity, CommitResult, TargetedWelcome, PassphraseBackup } from "../interface.js";
|
|
3
3
|
interface DeviceState {
|
|
4
4
|
deviceId: string;
|
|
5
5
|
ciphersuite: number;
|
|
@@ -11,10 +11,29 @@ interface PendingKeyPackage {
|
|
|
11
11
|
publicPackage: KeyPackage;
|
|
12
12
|
privatePackage: PrivateKeyPackage;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Tuning for the MLS secret-tree ratchet that backs replay/gap enforcement (RFC 9420). These are the
|
|
16
|
+
* legitimate dials — they tighten or loosen the window, they never disable enforcement. Omitted fields
|
|
17
|
+
* fall back to ts-mls's conservative defaults.
|
|
18
|
+
*/
|
|
19
|
+
export interface KeyRetentionOptions {
|
|
20
|
+
/** Max generations the ratchet will skip forward before rejecting (`gap-too-large`). ts-mls default 200. */
|
|
21
|
+
maximumForwardRatchetSteps?: number;
|
|
22
|
+
/** How many skipped per-sender message keys to retain (the out-of-order/reorder window). ts-mls default 10. */
|
|
23
|
+
retainKeysForGenerations?: number;
|
|
24
|
+
/** How many past epochs of receiver keys to retain (late delivery across a Commit). ts-mls default 4. */
|
|
25
|
+
retainKeysForEpochs?: number;
|
|
26
|
+
}
|
|
14
27
|
/** Options for {@link TsMlsSecureChatCrypto}. */
|
|
15
28
|
export interface TsMlsSecureChatCryptoOptions {
|
|
16
29
|
/** Numeric MLS ciphersuite id (RFC 9420). Defaults to 1 (the MTI baseline). */
|
|
17
30
|
ciphersuite?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Override the ts-mls key-retention window (replay/gap tolerance). Defaults to ts-mls's conservative
|
|
33
|
+
* values. Tightening (e.g. a smaller `maximumForwardRatchetSteps`) narrows the accepted gap; it cannot
|
|
34
|
+
* turn enforcement off. Applied consistently to created, joined, imported, and restored groups.
|
|
35
|
+
*/
|
|
36
|
+
keyRetention?: KeyRetentionOptions;
|
|
18
37
|
}
|
|
19
38
|
/**
|
|
20
39
|
* Real RFC 9420 MLS implementation of {@link SecureChatCrypto}, built on ts-mls. Construct via
|
|
@@ -27,6 +46,7 @@ export declare class TsMlsSecureChatCrypto implements SecureChatCrypto {
|
|
|
27
46
|
private credential?;
|
|
28
47
|
protected readonly pending: Map<string, PendingKeyPackage>;
|
|
29
48
|
protected readonly groups: Map<string, ClientState>;
|
|
49
|
+
private readonly clientConfig;
|
|
30
50
|
constructor(options?: TsMlsSecureChatCryptoOptions);
|
|
31
51
|
/** Lazily load + memoize the ciphersuite primitives. */
|
|
32
52
|
protected cs(): Promise<CiphersuiteImpl>;
|
|
@@ -63,6 +83,7 @@ export declare class TsMlsSecureChatCrypto implements SecureChatCrypto {
|
|
|
63
83
|
senderDeviceId: string;
|
|
64
84
|
epoch: bigint;
|
|
65
85
|
}>;
|
|
86
|
+
exportGroupIdentities(group: GroupHandle): Promise<GroupMemberIdentity[]>;
|
|
66
87
|
processWelcome(welcomePayload: Uint8Array): Promise<GroupHandle>;
|
|
67
88
|
processCommit(group: GroupHandle, commit: Uint8Array): Promise<GroupHandle>;
|
|
68
89
|
processProposal(group: GroupHandle, proposal: Uint8Array): Promise<void>;
|
|
@@ -70,8 +91,8 @@ export declare class TsMlsSecureChatCrypto implements SecureChatCrypto {
|
|
|
70
91
|
importGroupState(state: Uint8Array): Promise<GroupHandle>;
|
|
71
92
|
exportDeviceState(): Promise<Uint8Array>;
|
|
72
93
|
importDeviceState(state: Uint8Array): Promise<DeviceIdentity>;
|
|
73
|
-
exportBackup(
|
|
74
|
-
importBackup(
|
|
94
|
+
exportBackup(passphrase: string): Promise<PassphraseBackup>;
|
|
95
|
+
importBackup(passphrase: string, backup: PassphraseBackup): Promise<DeviceIdentity>;
|
|
75
96
|
/** Serialize identity (incl. signature private key) + the pending KeyPackage store to an opaque blob. */
|
|
76
97
|
protected serializeDeviceState(): Uint8Array;
|
|
77
98
|
private peerDeviceId;
|
|
@@ -7,16 +7,39 @@
|
|
|
7
7
|
//
|
|
8
8
|
// Security (CLAUDE.md #1): randomness is the platform CSPRNG (crypto.getRandomValues) + ts-mls/@noble;
|
|
9
9
|
// failed decode/decrypt/join fail closed (throw, drop); consumed key material is zeroized.
|
|
10
|
-
import { generateKeyPackageWithKey, defaultCapabilities, defaultLifetime, createGroup, createCommit, joinGroup, createApplicationMessage, processMessage, encodeMlsMessage, decodeMlsMessage, encodeGroupState, decodeGroupState, zeroOutUint8Array, acceptAll, emptyPskIndex, } from "ts-mls";
|
|
10
|
+
import { generateKeyPackageWithKey, defaultCapabilities, defaultLifetime, createGroup, createCommit, joinGroup, createApplicationMessage, processMessage, encodeMlsMessage, decodeMlsMessage, encodeGroupState, decodeGroupState, zeroOutUint8Array, acceptAll, emptyPskIndex, defaultKeyRetentionConfig, } from "ts-mls";
|
|
11
11
|
// makeKeyPackageRef + getGroupMembers + defaultClientConfig aren't re-exported from the package root;
|
|
12
12
|
// ts-mls exposes every module via its "./*.js" export, so deep-import them.
|
|
13
13
|
import { makeKeyPackageRef } from "ts-mls/keyPackage.js";
|
|
14
14
|
import { getGroupMembers } from "ts-mls/clientState.js";
|
|
15
15
|
import { defaultClientConfig } from "ts-mls/clientConfig.js";
|
|
16
|
+
import { SecureChatDecryptError } from "../interface.js";
|
|
16
17
|
import { DEFAULT_CIPHERSUITE_ID, loadCiphersuite } from "./ciphersuite.js";
|
|
18
|
+
import { sealBackup, openBackup } from "./backup.js";
|
|
17
19
|
import { toHex, fromHex } from "./hex.js";
|
|
18
20
|
const utf8 = (s) => new TextEncoder().encode(s);
|
|
19
21
|
const MLS_VERSION = "mls10";
|
|
22
|
+
/**
|
|
23
|
+
* Map a ts-mls decrypt/process failure to a {@link SecureChatDecryptError} with a classified reason.
|
|
24
|
+
* Matches on ts-mls's error messages/names (its secret-tree ratchet is the actual enforcement). The
|
|
25
|
+
* returned message is generic-by-reason — we never echo internal bytes or plaintext into the error.
|
|
26
|
+
*/
|
|
27
|
+
function classifyDecryptError(err) {
|
|
28
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
29
|
+
const name = err instanceof Error ? err.name : "";
|
|
30
|
+
let reason = "unknown";
|
|
31
|
+
if (/desired gen(?:eration)? in the past/i.test(msg))
|
|
32
|
+
reason = "replay";
|
|
33
|
+
else if (/too far in the future/i.test(msg))
|
|
34
|
+
reason = "gap-too-large";
|
|
35
|
+
else if (/epoch too old|former epoch/i.test(msg))
|
|
36
|
+
reason = "epoch-too-old";
|
|
37
|
+
else if (name === "CryptoVerificationError" || /signature|verif|auth/i.test(msg))
|
|
38
|
+
reason = "unauthenticated";
|
|
39
|
+
else if (name === "CodecError" || /decode|malformed/i.test(msg))
|
|
40
|
+
reason = "malformed";
|
|
41
|
+
return new SecureChatDecryptError(reason, `secure-chat: message decrypt rejected (${reason})`);
|
|
42
|
+
}
|
|
20
43
|
/**
|
|
21
44
|
* Real RFC 9420 MLS implementation of {@link SecureChatCrypto}, built on ts-mls. Construct via
|
|
22
45
|
* `createTsMlsSecureChatCrypto`; inject into `<SecureChatProvider crypto={…}>`.
|
|
@@ -27,6 +50,10 @@ export class TsMlsSecureChatCrypto {
|
|
|
27
50
|
this.pending = new Map(); // hex(ref) → kp
|
|
28
51
|
this.groups = new Map(); // hex(groupId) → state
|
|
29
52
|
this.ciphersuiteId = options.ciphersuite ?? DEFAULT_CIPHERSUITE_ID;
|
|
53
|
+
this.clientConfig = {
|
|
54
|
+
...defaultClientConfig,
|
|
55
|
+
keyRetentionConfig: { ...defaultKeyRetentionConfig, ...options.keyRetention },
|
|
56
|
+
};
|
|
30
57
|
}
|
|
31
58
|
/** Lazily load + memoize the ciphersuite primitives. */
|
|
32
59
|
async cs() {
|
|
@@ -77,7 +104,7 @@ export class TsMlsSecureChatCrypto {
|
|
|
77
104
|
const groupId = opts.mlsGroupId ?? crypto.getRandomValues(new Uint8Array(32));
|
|
78
105
|
// Seed the group with a fresh self KeyPackage (local-only; never published).
|
|
79
106
|
const self = await generateKeyPackageWithKey(this.credential, defaultCapabilities(), defaultLifetime, [], { signKey: dev.signKey, publicKey: dev.publicKey }, cs);
|
|
80
|
-
let state = await createGroup(groupId, self.publicPackage, self.privatePackage, [], cs);
|
|
107
|
+
let state = await createGroup(groupId, self.publicPackage, self.privatePackage, [], cs, this.clientConfig);
|
|
81
108
|
const adds = opts.initialMembers.map((m) => ({
|
|
82
109
|
proposalType: "add", add: { keyPackage: this.decodeKeyPackage(m.keyPackage) },
|
|
83
110
|
}));
|
|
@@ -124,16 +151,43 @@ export class TsMlsSecureChatCrypto {
|
|
|
124
151
|
async decryptMessage(group, ciphertext) {
|
|
125
152
|
const cs = await this.cs();
|
|
126
153
|
const state = this.lookupGroup(group);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
154
|
+
// ts-mls's secret-tree ratchet is the enforcement point: it throws on a replayed generation, an
|
|
155
|
+
// over-limit forward gap, a too-old epoch, or a failed authentication. We classify that throw (and
|
|
156
|
+
// decode failures) into a SecureChatDecryptError and re-raise it — and crucially we do NOT advance
|
|
157
|
+
// stored group state on failure (processMessage threw before returning newState), so a rejected
|
|
158
|
+
// message never ratchets us forward. Fail closed.
|
|
159
|
+
let res;
|
|
160
|
+
try {
|
|
161
|
+
const decoded = decodeMlsMessage(ciphertext, 0);
|
|
162
|
+
if (!decoded)
|
|
163
|
+
throw new SecureChatDecryptError("malformed", "secure-chat: malformed MLS message");
|
|
164
|
+
res = await processMessage(decoded[0], state, emptyPskIndex, acceptAll, cs);
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
throw err instanceof SecureChatDecryptError ? err : classifyDecryptError(err);
|
|
168
|
+
}
|
|
131
169
|
this.zeroize(res.consumed);
|
|
132
170
|
this.groups.set(toHex(group.mlsGroupId), res.newState);
|
|
133
|
-
if (res.kind !== "applicationMessage")
|
|
134
|
-
throw new
|
|
171
|
+
if (res.kind !== "applicationMessage") {
|
|
172
|
+
throw new SecureChatDecryptError("malformed", "secure-chat: expected an application message");
|
|
173
|
+
}
|
|
135
174
|
return { plaintext: res.message, senderDeviceId: this.peerDeviceId(res.newState), epoch: res.newState.groupContext.epoch };
|
|
136
175
|
}
|
|
176
|
+
async exportGroupIdentities(group) {
|
|
177
|
+
const state = this.lookupGroup(group);
|
|
178
|
+
const out = [];
|
|
179
|
+
// Read the roster from the MLS ratchet tree (same source peerDeviceId uses). Only basic-credential
|
|
180
|
+
// leaves carry a device-id identity; skip anything else rather than guess.
|
|
181
|
+
for (const leaf of getGroupMembers(state)) {
|
|
182
|
+
if (leaf.credential.credentialType !== "basic")
|
|
183
|
+
continue;
|
|
184
|
+
out.push({
|
|
185
|
+
deviceId: new TextDecoder().decode(leaf.credential.identity),
|
|
186
|
+
signaturePublicKey: leaf.signaturePublicKey,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
137
191
|
async processWelcome(welcomePayload) {
|
|
138
192
|
const cs = await this.cs();
|
|
139
193
|
const decoded = decodeMlsMessage(welcomePayload, 0);
|
|
@@ -154,8 +208,10 @@ export class TsMlsSecureChatCrypto {
|
|
|
154
208
|
}
|
|
155
209
|
if (!matched || !matchedRef)
|
|
156
210
|
throw new Error("secure-chat: no matching KeyPackage for this Welcome");
|
|
157
|
-
// ratchetTree omitted — it rode in via the creator's ratchetTreeExtension.
|
|
158
|
-
|
|
211
|
+
// ratchetTree omitted — it rode in via the creator's ratchetTreeExtension. Pass our clientConfig
|
|
212
|
+
// (positional args 6/7 — ratchetTree/resumingFromState — are unused here) so the joined group gets
|
|
213
|
+
// the configured key-retention window, not ts-mls's default.
|
|
214
|
+
const state = await joinGroup(welcome, matched.publicPackage, matched.privatePackage, emptyPskIndex, cs, undefined, undefined, this.clientConfig);
|
|
159
215
|
this.pending.delete(matchedRef); // one-time: consumed
|
|
160
216
|
this.groups.set(toHex(state.groupContext.groupId), state);
|
|
161
217
|
return { mlsGroupId: state.groupContext.groupId, epoch: state.groupContext.epoch };
|
|
@@ -193,7 +249,9 @@ export class TsMlsSecureChatCrypto {
|
|
|
193
249
|
const decoded = decodeGroupState(state, 0);
|
|
194
250
|
if (!decoded)
|
|
195
251
|
throw new Error("secure-chat: corrupt group state");
|
|
196
|
-
|
|
252
|
+
// Reattach OUR clientConfig (not ts-mls's default) so the configured key-retention window survives
|
|
253
|
+
// the persistence round-trip — encodeGroupState drops the (callback-bearing) config.
|
|
254
|
+
const clientState = { ...decoded[0], clientConfig: this.clientConfig };
|
|
197
255
|
this.groups.set(toHex(clientState.groupContext.groupId), clientState);
|
|
198
256
|
return { mlsGroupId: clientState.groupContext.groupId, epoch: clientState.groupContext.epoch };
|
|
199
257
|
}
|
|
@@ -221,13 +279,34 @@ export class TsMlsSecureChatCrypto {
|
|
|
221
279
|
}
|
|
222
280
|
return { deviceId: p.deviceId, signaturePublicKey: this.device.publicKey, credential: utf8(p.deviceId), ciphersuite: p.ciphersuite };
|
|
223
281
|
}
|
|
224
|
-
//
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
|
|
282
|
+
// Passphrase backup of ALL local key material: the device identity (incl. the signature private
|
|
283
|
+
// key + pending KeyPackages, via serializeDeviceState) and every joined group's full MLS state.
|
|
284
|
+
// The argon2id KDF + AEAD live in ./backup.ts; here we just (de)serialize the payload. The blob is
|
|
285
|
+
// opaque to the blind server — only ciphertext crosses the wire.
|
|
286
|
+
async exportBackup(passphrase) {
|
|
287
|
+
const payload = {
|
|
288
|
+
v: 1,
|
|
289
|
+
device: toHex(this.serializeDeviceState()),
|
|
290
|
+
groups: [...this.groups.values()].map((st) => toHex(encodeGroupState(st))),
|
|
291
|
+
};
|
|
292
|
+
return sealBackup(utf8(JSON.stringify(payload)), passphrase);
|
|
228
293
|
}
|
|
229
|
-
async importBackup(
|
|
230
|
-
|
|
294
|
+
async importBackup(passphrase, backup) {
|
|
295
|
+
const plain = await openBackup(backup, passphrase);
|
|
296
|
+
const payload = JSON.parse(new TextDecoder().decode(plain));
|
|
297
|
+
if (payload.v !== 1)
|
|
298
|
+
throw new Error(`secure-chat: unsupported backup payload version ${payload.v}`);
|
|
299
|
+
// Restore the device identity first (also clears + repopulates the pending KeyPackages).
|
|
300
|
+
const identity = await this.importDeviceState(fromHex(payload.device));
|
|
301
|
+
// Then every group's full state, keyed by its MLS group id (mirrors importGroupState).
|
|
302
|
+
for (const g of payload.groups) {
|
|
303
|
+
const decoded = decodeGroupState(fromHex(g), 0);
|
|
304
|
+
if (!decoded)
|
|
305
|
+
throw new Error("secure-chat: corrupt group state in backup");
|
|
306
|
+
const clientState = { ...decoded[0], clientConfig: this.clientConfig };
|
|
307
|
+
this.groups.set(toHex(clientState.groupContext.groupId), clientState);
|
|
308
|
+
}
|
|
309
|
+
return identity;
|
|
231
310
|
}
|
|
232
311
|
/** Serialize identity (incl. signature private key) + the pending KeyPackage store to an opaque blob. */
|
|
233
312
|
serializeDeviceState() {
|