@agentunion/fastaun 0.2.20 → 0.3.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 (105) hide show
  1. package/CHANGELOG.md +63 -23
  2. package/_packed_docs/CHANGELOG.md +63 -23
  3. package/_packed_docs/design/2026-05-22-aun-rpc-trace-enhancement.md +542 -0
  4. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1 -24
  5. package/_packed_docs/protocol/15-/347/246/273/347/272/277/346/216/250/351/200/201/351/200/232/347/237/245/345/215/217/350/256/256.md +419 -0
  6. package/_packed_docs/protocol/index.md +13 -3
  7. package/_packed_docs/python-sdk-v2-only-changelog.md +189 -0
  8. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +39 -16
  9. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +131 -39
  10. package/_packed_docs/sdk/09-message-rpc-manual.md +30 -67
  11. package/dist/auth.js +26 -7
  12. package/dist/auth.js.map +1 -1
  13. package/dist/client.d.ts +117 -166
  14. package/dist/client.js +2130 -3419
  15. package/dist/client.js.map +1 -1
  16. package/dist/config.d.ts +0 -4
  17. package/dist/config.js +0 -4
  18. package/dist/config.js.map +1 -1
  19. package/dist/e2ee.d.ts +5 -139
  20. package/dist/e2ee.js +4 -1151
  21. package/dist/e2ee.js.map +1 -1
  22. package/dist/errors.d.ts +0 -8
  23. package/dist/errors.js +0 -14
  24. package/dist/errors.js.map +1 -1
  25. package/dist/index.d.ts +9 -5
  26. package/dist/index.js +6 -3
  27. package/dist/index.js.map +1 -1
  28. package/dist/keystore/aid-db.d.ts +12 -61
  29. package/dist/keystore/aid-db.js +41 -539
  30. package/dist/keystore/aid-db.js.map +1 -1
  31. package/dist/keystore/file.d.ts +5 -41
  32. package/dist/keystore/file.js +8 -64
  33. package/dist/keystore/file.js.map +1 -1
  34. package/dist/keystore/index.d.ts +1 -49
  35. package/dist/namespaces/auth.d.ts +8 -0
  36. package/dist/namespaces/auth.js +169 -2
  37. package/dist/namespaces/auth.js.map +1 -1
  38. package/dist/protected-headers.d.ts +13 -0
  39. package/dist/protected-headers.js +47 -0
  40. package/dist/protected-headers.js.map +1 -0
  41. package/dist/seq-tracker.d.ts +7 -2
  42. package/dist/seq-tracker.js +33 -13
  43. package/dist/seq-tracker.js.map +1 -1
  44. package/dist/transport.d.ts +11 -1
  45. package/dist/transport.js +255 -6
  46. package/dist/transport.js.map +1 -1
  47. package/dist/types.d.ts +0 -56
  48. package/dist/v2/crypto/aead.d.ts +20 -0
  49. package/dist/v2/crypto/aead.js +59 -0
  50. package/dist/v2/crypto/aead.js.map +1 -0
  51. package/dist/v2/crypto/canonical.d.ts +20 -0
  52. package/dist/v2/crypto/canonical.js +119 -0
  53. package/dist/v2/crypto/canonical.js.map +1 -0
  54. package/dist/v2/crypto/dh-path.d.ts +39 -0
  55. package/dist/v2/crypto/dh-path.js +55 -0
  56. package/dist/v2/crypto/dh-path.js.map +1 -0
  57. package/dist/v2/crypto/ecdh.d.ts +29 -0
  58. package/dist/v2/crypto/ecdh.js +122 -0
  59. package/dist/v2/crypto/ecdh.js.map +1 -0
  60. package/dist/v2/crypto/ecdsa.d.ts +29 -0
  61. package/dist/v2/crypto/ecdsa.js +120 -0
  62. package/dist/v2/crypto/ecdsa.js.map +1 -0
  63. package/dist/v2/crypto/hkdf.d.ts +19 -0
  64. package/dist/v2/crypto/hkdf.js +47 -0
  65. package/dist/v2/crypto/hkdf.js.map +1 -0
  66. package/dist/v2/crypto/index.d.ts +8 -0
  67. package/dist/v2/crypto/index.js +8 -0
  68. package/dist/v2/crypto/index.js.map +1 -0
  69. package/dist/v2/crypto/recipients.d.ts +32 -0
  70. package/dist/v2/crypto/recipients.js +183 -0
  71. package/dist/v2/crypto/recipients.js.map +1 -0
  72. package/dist/v2/e2ee/decrypt.d.ts +29 -0
  73. package/dist/v2/e2ee/decrypt.js +159 -0
  74. package/dist/v2/e2ee/decrypt.js.map +1 -0
  75. package/dist/v2/e2ee/encrypt-group.d.ts +17 -0
  76. package/dist/v2/e2ee/encrypt-group.js +143 -0
  77. package/dist/v2/e2ee/encrypt-group.js.map +1 -0
  78. package/dist/v2/e2ee/encrypt-p2p.d.ts +31 -0
  79. package/dist/v2/e2ee/encrypt-p2p.js +190 -0
  80. package/dist/v2/e2ee/encrypt-p2p.js.map +1 -0
  81. package/dist/v2/e2ee/index.d.ts +9 -0
  82. package/dist/v2/e2ee/index.js +9 -0
  83. package/dist/v2/e2ee/index.js.map +1 -0
  84. package/dist/v2/e2ee/metadata-auth.d.ts +15 -0
  85. package/dist/v2/e2ee/metadata-auth.js +50 -0
  86. package/dist/v2/e2ee/metadata-auth.js.map +1 -0
  87. package/dist/v2/e2ee/types.d.ts +57 -0
  88. package/dist/v2/e2ee/types.js +7 -0
  89. package/dist/v2/e2ee/types.js.map +1 -0
  90. package/dist/v2/session/index.d.ts +4 -0
  91. package/dist/v2/session/index.js +3 -0
  92. package/dist/v2/session/index.js.map +1 -0
  93. package/dist/v2/session/keystore.d.ts +50 -0
  94. package/dist/v2/session/keystore.js +138 -0
  95. package/dist/v2/session/keystore.js.map +1 -0
  96. package/dist/v2/session/session.d.ts +124 -0
  97. package/dist/v2/session/session.js +318 -0
  98. package/dist/v2/session/session.js.map +1 -0
  99. package/dist/v2/state/commitment.d.ts +58 -0
  100. package/dist/v2/state/commitment.js +85 -0
  101. package/dist/v2/state/commitment.js.map +1 -0
  102. package/dist/v2/state/index.d.ts +2 -0
  103. package/dist/v2/state/index.js +2 -0
  104. package/dist/v2/state/index.js.map +1 -0
  105. package/package.json +4 -3
@@ -0,0 +1,32 @@
1
+ /**
2
+ * AUN E2EE V2: Recipients 排序与 Merkle Digest
3
+ *
4
+ * 规范引用:§5.3 / §10.3
5
+ *
6
+ * - 行排序:(aid asc, device_id asc, role asc) 字典序
7
+ * - 每行固定 8 字段:[aid, device_id, role, key_source, fp, spk_id, wrap_nonce, wrapped_key]
8
+ * - Digest = Merkle root(leaf/inner 各有独立前缀)
9
+ * - 奇数节点复制最后一个
10
+ */
11
+ export interface ProofStep {
12
+ sibling: string;
13
+ position: 'L' | 'R';
14
+ }
15
+ /** 按 (aid, device_id, role) 字典序稳定排序 recipients。 */
16
+ export declare function sortRecipients(rows: string[][]): string[][];
17
+ /** 计算单个 recipient 行的 leaf hash(32 字节)。 */
18
+ export declare function computeLeafHash(row: string[]): Uint8Array;
19
+ /**
20
+ * 计算 recipients 的 Merkle root(hex)。空列表返回空字符串(与 Python 一致)。
21
+ */
22
+ export declare function computeMerkleRoot(rows: string[][]): string;
23
+ /** 兼容入口,等价 computeMerkleRoot。调用方应先调 sortRecipients。 */
24
+ export declare function computeRecipientsDigest(rows: string[][]): string;
25
+ /**
26
+ * 为 targetIndex 行生成 Merkle proof(log N 步)。
27
+ */
28
+ export declare function computeMerkleProof(rows: string[][], targetIndex: number): ProofStep[];
29
+ /**
30
+ * 验证 leaf + proof 重建出的 root 与期望值一致。
31
+ */
32
+ export declare function verifyMerkleProof(leaf: Uint8Array, proof: ProofStep[], expectedRootHex: string): boolean;
@@ -0,0 +1,183 @@
1
+ /**
2
+ * AUN E2EE V2: Recipients 排序与 Merkle Digest
3
+ *
4
+ * 规范引用:§5.3 / §10.3
5
+ *
6
+ * - 行排序:(aid asc, device_id asc, role asc) 字典序
7
+ * - 每行固定 8 字段:[aid, device_id, role, key_source, fp, spk_id, wrap_nonce, wrapped_key]
8
+ * - Digest = Merkle root(leaf/inner 各有独立前缀)
9
+ * - 奇数节点复制最后一个
10
+ */
11
+ import { createHash } from 'node:crypto';
12
+ const TEXT = new TextEncoder();
13
+ const LEAF_PREFIX = TEXT.encode('AUN-V2-RCPT-LEAF-v1');
14
+ const NODE_PREFIX = TEXT.encode('AUN-V2-RCPT-NODE-v1');
15
+ /** 按 (aid, device_id, role) 字典序稳定排序 recipients。 */
16
+ export function sortRecipients(rows) {
17
+ return [...rows].sort((a, b) => {
18
+ const ka0 = a[0] ?? '';
19
+ const kb0 = b[0] ?? '';
20
+ if (ka0 !== kb0)
21
+ return ka0 < kb0 ? -1 : 1;
22
+ const ka1 = a[1] ?? '';
23
+ const kb1 = b[1] ?? '';
24
+ if (ka1 !== kb1)
25
+ return ka1 < kb1 ? -1 : 1;
26
+ const ka2 = a[2] ?? '';
27
+ const kb2 = b[2] ?? '';
28
+ if (ka2 !== kb2)
29
+ return ka2 < kb2 ? -1 : 1;
30
+ return 0;
31
+ });
32
+ }
33
+ /**
34
+ * wrap_nonce / wrapped_key 字段优先按 base64 解码,失败则按 utf-8 字节回退(与 Python 行为一致)。
35
+ */
36
+ function decodeOrRaw(value) {
37
+ if (!value)
38
+ return new Uint8Array(0);
39
+ // Node Buffer.from(..., 'base64') 对非法字符会忽略而非抛错,
40
+ // 因此校验"再编码回去"是否一致来判断输入是否合法 base64。
41
+ // 这与 Python base64.b64decode(value) 的行为相近:
42
+ // 不合法时 Python 抛错 → 我们 fallback 到 utf-8。
43
+ // 不过 Python 默认非严格模式也容错;这里采用与 Python 完全等价的判定:
44
+ // 1) 仅含 base64 字符集 [A-Za-z0-9+/=]
45
+ // 2) 长度是 4 的倍数
46
+ // 否则按 utf-8 处理。
47
+ if (isLikelyBase64(value)) {
48
+ try {
49
+ const decoded = Buffer.from(value, 'base64');
50
+ // 双重校验:重编码与原值一致(忽略 padding 差异)。
51
+ const reencoded = decoded.toString('base64');
52
+ // 比较时归一化 padding:Python 会抛 binascii.Error 在 padding 不正确时。
53
+ if (reencoded === value || reencoded.replace(/=+$/, '') === value.replace(/=+$/, '')) {
54
+ return new Uint8Array(decoded);
55
+ }
56
+ }
57
+ catch {
58
+ /* fallthrough */
59
+ }
60
+ }
61
+ return new Uint8Array(TEXT.encode(value));
62
+ }
63
+ function isLikelyBase64(s) {
64
+ if (s.length === 0)
65
+ return false;
66
+ if (s.length % 4 !== 0)
67
+ return false;
68
+ return /^[A-Za-z0-9+/]+={0,2}$/.test(s);
69
+ }
70
+ /** 计算单个 recipient 行的 leaf hash(32 字节)。 */
71
+ export function computeLeafHash(row) {
72
+ const aid = TEXT.encode(String(row[0] ?? ''));
73
+ const deviceId = TEXT.encode(String(row[1] ?? ''));
74
+ const role = TEXT.encode(String(row[2] ?? ''));
75
+ const keySource = TEXT.encode(String(row[3] ?? ''));
76
+ const fp = TEXT.encode(String(row[4] ?? ''));
77
+ const spkId = TEXT.encode(String(row[5] ?? ''));
78
+ const wrapNonce = decodeOrRaw(String(row[6] ?? ''));
79
+ const wrappedKey = decodeOrRaw(String(row[7] ?? ''));
80
+ const h = createHash('sha256');
81
+ h.update(LEAF_PREFIX);
82
+ h.update(aid);
83
+ h.update(Uint8Array.of(0));
84
+ h.update(deviceId);
85
+ h.update(Uint8Array.of(0));
86
+ h.update(role);
87
+ h.update(Uint8Array.of(0));
88
+ h.update(keySource);
89
+ h.update(Uint8Array.of(0));
90
+ h.update(fp);
91
+ h.update(Uint8Array.of(0));
92
+ h.update(spkId);
93
+ h.update(Uint8Array.of(0));
94
+ h.update(wrapNonce);
95
+ h.update(wrappedKey);
96
+ return new Uint8Array(h.digest());
97
+ }
98
+ function nodeHash(left, right) {
99
+ const h = createHash('sha256');
100
+ h.update(NODE_PREFIX);
101
+ h.update(left);
102
+ h.update(right);
103
+ return new Uint8Array(h.digest());
104
+ }
105
+ function merkleRootFromLeaves(leaves) {
106
+ if (leaves.length === 1)
107
+ return leaves[0];
108
+ let layer = [...leaves];
109
+ while (layer.length > 1) {
110
+ if (layer.length % 2 === 1)
111
+ layer.push(layer[layer.length - 1]);
112
+ const next = [];
113
+ for (let i = 0; i < layer.length; i += 2) {
114
+ next.push(nodeHash(layer[i], layer[i + 1]));
115
+ }
116
+ layer = next;
117
+ }
118
+ return layer[0];
119
+ }
120
+ /**
121
+ * 计算 recipients 的 Merkle root(hex)。空列表返回空字符串(与 Python 一致)。
122
+ */
123
+ export function computeMerkleRoot(rows) {
124
+ if (rows.length === 0)
125
+ return '';
126
+ const leaves = rows.map(computeLeafHash);
127
+ return Buffer.from(merkleRootFromLeaves(leaves)).toString('hex');
128
+ }
129
+ /** 兼容入口,等价 computeMerkleRoot。调用方应先调 sortRecipients。 */
130
+ export function computeRecipientsDigest(rows) {
131
+ return computeMerkleRoot(rows);
132
+ }
133
+ /**
134
+ * 为 targetIndex 行生成 Merkle proof(log N 步)。
135
+ */
136
+ export function computeMerkleProof(rows, targetIndex) {
137
+ if (rows.length === 0 || targetIndex < 0 || targetIndex >= rows.length)
138
+ return [];
139
+ const leaves = rows.map(computeLeafHash);
140
+ const proof = [];
141
+ let layer = [...leaves];
142
+ let idx = targetIndex;
143
+ while (layer.length > 1) {
144
+ if (layer.length % 2 === 1)
145
+ layer.push(layer[layer.length - 1]);
146
+ const siblingIdx = idx ^ 1;
147
+ proof.push({
148
+ sibling: Buffer.from(layer[siblingIdx]).toString('hex'),
149
+ position: siblingIdx > idx ? 'R' : 'L',
150
+ });
151
+ const next = [];
152
+ for (let i = 0; i < layer.length; i += 2) {
153
+ next.push(nodeHash(layer[i], layer[i + 1]));
154
+ }
155
+ layer = next;
156
+ idx = Math.floor(idx / 2);
157
+ }
158
+ return proof;
159
+ }
160
+ /**
161
+ * 验证 leaf + proof 重建出的 root 与期望值一致。
162
+ */
163
+ export function verifyMerkleProof(leaf, proof, expectedRootHex) {
164
+ if (!expectedRootHex)
165
+ return false;
166
+ let cur = leaf;
167
+ for (const step of proof) {
168
+ if (!/^[0-9a-fA-F]*$/.test(step.sibling) || step.sibling.length % 2 !== 0)
169
+ return false;
170
+ const sibling = Uint8Array.from(Buffer.from(step.sibling, 'hex'));
171
+ if (step.position === 'L') {
172
+ cur = nodeHash(sibling, cur);
173
+ }
174
+ else if (step.position === 'R') {
175
+ cur = nodeHash(cur, sibling);
176
+ }
177
+ else {
178
+ return false;
179
+ }
180
+ }
181
+ return Buffer.from(cur).toString('hex') === expectedRootHex;
182
+ }
183
+ //# sourceMappingURL=recipients.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipients.js","sourceRoot":"","sources":["../../../src/v2/crypto/recipients.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * AUN E2EE V2: 统一解密引擎
3
+ *
4
+ * 支持 P2P 和 Group 消息解密(按 envelope.type / 字段结构分流)。
5
+ * 纯计算,无 IO。
6
+ *
7
+ * 与 Python `aun_core.v2.e2ee.decrypt.decrypt_message` 对齐。
8
+ *
9
+ * 流程:
10
+ * 1. 验 sender_signature
11
+ * 2. 找自己的 row(recipients 数组或 per-device recipient + 可选 merkle_proof)
12
+ * 3. 计算 wrap_salt
13
+ * 4. 派生 wrap_key(3DH 或 1DH)
14
+ * 5. 解 master_key
15
+ * 6. 解 body
16
+ * 7. 解析 JSON payload
17
+ */
18
+ /**
19
+ * 解密 V2 加密消息(P2P 或 Group)。
20
+ *
21
+ * @param envelope 完整 envelope(已 JSON.parse 的对象)
22
+ * @param selfAid 接收方 AID
23
+ * @param selfDeviceId 接收方 device_id
24
+ * @param selfIkPriv 接收方 IK 私钥(32B scalar)
25
+ * @param selfSpkPriv 接收方 SPK 私钥(32B scalar);undefined/null 表示无 SPK(1DH)
26
+ * @param senderPubDer 发送方 AID 主公钥(DER),用于验签 + 3DH 接收侧 DH2
27
+ * @returns 解密后的 payload;null 表示在 recipients 中找不到自己的 row
28
+ */
29
+ export declare function decryptMessage(envelope: Record<string, unknown>, selfAid: string, selfDeviceId: string, selfIkPriv: Uint8Array, selfSpkPriv: Uint8Array | undefined, senderPubDer: Uint8Array): Record<string, unknown> | null;
@@ -0,0 +1,159 @@
1
+ /**
2
+ * AUN E2EE V2: 统一解密引擎
3
+ *
4
+ * 支持 P2P 和 Group 消息解密(按 envelope.type / 字段结构分流)。
5
+ * 纯计算,无 IO。
6
+ *
7
+ * 与 Python `aun_core.v2.e2ee.decrypt.decrypt_message` 对齐。
8
+ *
9
+ * 流程:
10
+ * 1. 验 sender_signature
11
+ * 2. 找自己的 row(recipients 数组或 per-device recipient + 可选 merkle_proof)
12
+ * 3. 计算 wrap_salt
13
+ * 4. 派生 wrap_key(3DH 或 1DH)
14
+ * 5. 解 master_key
15
+ * 6. 解 body
16
+ * 7. 解析 JSON payload
17
+ */
18
+ import { createHash } from 'node:crypto';
19
+ import { canonicalJson } from '../crypto/canonical.js';
20
+ import { ecdsaVerifyRaw } from '../crypto/ecdsa.js';
21
+ import { ecdhComputeShared } from '../crypto/ecdh.js';
22
+ import { hkdfSha256 } from '../crypto/hkdf.js';
23
+ import { aesGcmDecrypt } from '../crypto/aead.js';
24
+ import { computeLeafHash, computeRecipientsDigest, verifyMerkleProof, } from '../crypto/recipients.js';
25
+ import { SUITE_NAME } from './types.js';
26
+ const TEXT = new TextEncoder();
27
+ const INFO_3DH = TEXT.encode('AUN-V2-3DH');
28
+ const INFO_1DH = TEXT.encode('AUN-V2-1DH');
29
+ /**
30
+ * 解密 V2 加密消息(P2P 或 Group)。
31
+ *
32
+ * @param envelope 完整 envelope(已 JSON.parse 的对象)
33
+ * @param selfAid 接收方 AID
34
+ * @param selfDeviceId 接收方 device_id
35
+ * @param selfIkPriv 接收方 IK 私钥(32B scalar)
36
+ * @param selfSpkPriv 接收方 SPK 私钥(32B scalar);undefined/null 表示无 SPK(1DH)
37
+ * @param senderPubDer 发送方 AID 主公钥(DER),用于验签 + 3DH 接收侧 DH2
38
+ * @returns 解密后的 payload;null 表示在 recipients 中找不到自己的 row
39
+ */
40
+ export function decryptMessage(envelope, selfAid, selfDeviceId, selfIkPriv, selfSpkPriv, senderPubDer) {
41
+ // 1. 验签
42
+ if (!verifySenderSignature(envelope, senderPubDer)) {
43
+ throw new Error('sender_signature verification failed');
44
+ }
45
+ // 2. 找自己的 row
46
+ let row = null;
47
+ if (Array.isArray(envelope.recipients)) {
48
+ const rows = envelope.recipients;
49
+ const expectedDigest = String(envelope.recipients_digest ?? '');
50
+ if (computeRecipientsDigest(rows) !== expectedDigest) {
51
+ throw new Error('recipients_digest mismatch');
52
+ }
53
+ row = findMyRow(rows, selfAid, selfDeviceId);
54
+ if (!row)
55
+ return null;
56
+ }
57
+ else if (envelope.recipient && typeof envelope.recipient === 'object') {
58
+ const r = envelope.recipient;
59
+ row = [
60
+ String(r.aid ?? ''),
61
+ String(r.device_id ?? ''),
62
+ String(r.role ?? ''),
63
+ String(r.key_source ?? ''),
64
+ String(r.fp ?? ''),
65
+ String(r.spk_id ?? ''),
66
+ String(r.wrap_nonce ?? ''),
67
+ String(r.wrapped_key ?? ''),
68
+ ];
69
+ // per-device 形态可能携带 merkle_proof
70
+ const proof = envelope.merkle_proof;
71
+ const expectedRoot = String(envelope.recipients_digest ?? '');
72
+ if (proof && expectedRoot) {
73
+ const leaf = computeLeafHash(row);
74
+ if (!verifyMerkleProof(leaf, proof, expectedRoot)) {
75
+ // 服务端篡改/替换 wrap,拒绝
76
+ return null;
77
+ }
78
+ }
79
+ }
80
+ else {
81
+ return null;
82
+ }
83
+ // 3. wrap_salt
84
+ const senderSessionPkDer = new Uint8Array(Buffer.from(String(envelope.sender_session_pk ?? ''), 'base64'));
85
+ const aad = envelope.aad;
86
+ const aadBytes = canonicalJson(aad);
87
+ const suiteStr = String(envelope.suite ?? SUITE_NAME);
88
+ const wrapSalt = computeWrapSalt(aadBytes, senderSessionPkDer, suiteStr);
89
+ // 4. wrap_key
90
+ const wrapKey = computeWrapKey(row, selfIkPriv, selfSpkPriv, senderSessionPkDer, senderPubDer, wrapSalt);
91
+ // 5. decrypt master_key
92
+ const wrapNonce = new Uint8Array(Buffer.from(row[6], 'base64'));
93
+ const wrappedKey = new Uint8Array(Buffer.from(row[7], 'base64'));
94
+ if (wrappedKey.length < 16) {
95
+ throw new Error('wrapped_key too short');
96
+ }
97
+ const wrappedCt = wrappedKey.subarray(0, wrappedKey.length - 16);
98
+ const wrappedTag = wrappedKey.subarray(wrappedKey.length - 16);
99
+ const masterKey = aesGcmDecrypt(wrapKey, wrapNonce, wrappedCt, wrappedTag, new Uint8Array(0));
100
+ // 6. decrypt body
101
+ const msgNonce = new Uint8Array(Buffer.from(String(envelope.nonce ?? ''), 'base64'));
102
+ const ct = new Uint8Array(Buffer.from(String(envelope.ciphertext ?? ''), 'base64'));
103
+ const tag = new Uint8Array(Buffer.from(String(envelope.tag ?? ''), 'base64'));
104
+ const plaintext = aesGcmDecrypt(masterKey, msgNonce, ct, tag, aadBytes);
105
+ // 7. parse JSON
106
+ return JSON.parse(Buffer.from(plaintext).toString('utf-8'));
107
+ }
108
+ function computeWrapSalt(aadBytes, senderSessionPkDer, suiteStr) {
109
+ const suiteBytes = TEXT.encode(suiteStr);
110
+ const h = createHash('sha256');
111
+ h.update(Buffer.from(aadBytes));
112
+ h.update(Buffer.from(senderSessionPkDer));
113
+ h.update(Buffer.from(suiteBytes));
114
+ return new Uint8Array(h.digest()).subarray(0, 16);
115
+ }
116
+ function computeWrapKey(row, selfIkPriv, selfSpkPriv, senderSessionPkDer, senderMasterPkDer, salt) {
117
+ const spkId = row[5];
118
+ if (spkId && selfSpkPriv) {
119
+ // 3DH 接收方:DH1=ECDH(self_ik, sender_session);DH2=ECDH(self_spk, sender_master);DH3=ECDH(self_spk, sender_session)
120
+ const dh1 = ecdhComputeShared(selfIkPriv, senderSessionPkDer);
121
+ const dh2 = ecdhComputeShared(selfSpkPriv, senderMasterPkDer);
122
+ const dh3 = ecdhComputeShared(selfSpkPriv, senderSessionPkDer);
123
+ const ikm = new Uint8Array(96);
124
+ ikm.set(dh1, 0);
125
+ ikm.set(dh2, 32);
126
+ ikm.set(dh3, 64);
127
+ return hkdfSha256(ikm, salt, INFO_3DH, 32);
128
+ }
129
+ // 1DH 接收方
130
+ const dh1 = ecdhComputeShared(selfIkPriv, senderSessionPkDer);
131
+ return hkdfSha256(dh1, salt, INFO_1DH, 32);
132
+ }
133
+ function findMyRow(rows, aid, deviceId) {
134
+ for (const r of rows) {
135
+ if (r[0] === aid && r[1] === deviceId)
136
+ return r;
137
+ }
138
+ return null;
139
+ }
140
+ function verifySenderSignature(envelope, senderPubDer) {
141
+ const sigStr = envelope.sender_signature;
142
+ const ctStr = envelope.ciphertext;
143
+ const tagStr = envelope.tag;
144
+ const digestHex = envelope.recipients_digest;
145
+ if (typeof sigStr !== 'string' ||
146
+ typeof ctStr !== 'string' ||
147
+ typeof tagStr !== 'string' ||
148
+ typeof digestHex !== 'string') {
149
+ return false;
150
+ }
151
+ const sig = new Uint8Array(Buffer.from(sigStr, 'base64'));
152
+ const ct = Buffer.from(ctStr, 'base64');
153
+ const tag = Buffer.from(tagStr, 'base64');
154
+ const aadBytes = canonicalJson(envelope.aad);
155
+ const digestBytes = Buffer.from(digestHex, 'hex');
156
+ const signInput = new Uint8Array(Buffer.concat([ct, tag, Buffer.from(aadBytes), digestBytes]));
157
+ return ecdsaVerifyRaw(senderPubDer, sig, signInput);
158
+ }
159
+ //# sourceMappingURL=decrypt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decrypt.js","sourceRoot":"","sources":["../../../src/v2/e2ee/decrypt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * AUN E2EE V2: Group 加密引擎
3
+ *
4
+ * 构造完整的 `e2ee.group_encrypted` envelope。纯计算,无 IO。
5
+ *
6
+ * 与 Python `aun_core.v2.e2ee.encrypt_group.encrypt_group_message` 对齐。
7
+ *
8
+ * 与 P2P 同构,AAD 多 group_id / epoch / state_commitment;envelope 顶层多
9
+ * group_id / epoch,无 to / t_supplement。
10
+ */
11
+ import { Sender, Target, EncryptOptions, StateCommitmentAAD } from './types.js';
12
+ /**
13
+ * 构造完整的 V2 Group 加密 envelope。
14
+ *
15
+ * @param stateCommitment 可选;缺省时写入占位(state_version=0)以兼容未启用 state 的群。
16
+ */
17
+ export declare function encryptGroupMessage(sender: Sender, groupId: string, epoch: number, targets: Target[], payload: Record<string, unknown>, opts?: EncryptOptions, stateCommitment?: StateCommitmentAAD | null): Record<string, unknown>;
@@ -0,0 +1,143 @@
1
+ /**
2
+ * AUN E2EE V2: Group 加密引擎
3
+ *
4
+ * 构造完整的 `e2ee.group_encrypted` envelope。纯计算,无 IO。
5
+ *
6
+ * 与 Python `aun_core.v2.e2ee.encrypt_group.encrypt_group_message` 对齐。
7
+ *
8
+ * 与 P2P 同构,AAD 多 group_id / epoch / state_commitment;envelope 顶层多
9
+ * group_id / epoch,无 to / t_supplement。
10
+ */
11
+ import { createHash, randomUUID, randomBytes } from 'node:crypto';
12
+ import { canonicalJson } from '../crypto/canonical.js';
13
+ import { ecdsaSignRaw } from '../crypto/ecdsa.js';
14
+ import { aesGcmEncrypt } from '../crypto/aead.js';
15
+ import { generateP256Keypair } from '../crypto/ecdh.js';
16
+ import { compute3DHWrap, compute1DHWrap } from '../crypto/dh-path.js';
17
+ import { sortRecipients, computeRecipientsDigest } from '../crypto/recipients.js';
18
+ import { SUITE_NAME, } from './types.js';
19
+ import { withMetadataAuth, PROTECTED_HEADERS_DOMAIN, PROTECTED_CONTEXT_DOMAIN } from './metadata-auth.js';
20
+ import { normalizeProtectedHeaders } from './encrypt-p2p.js';
21
+ const TEXT = new TextEncoder();
22
+ /**
23
+ * 构造完整的 V2 Group 加密 envelope。
24
+ *
25
+ * @param stateCommitment 可选;缺省时写入占位(state_version=0)以兼容未启用 state 的群。
26
+ */
27
+ export function encryptGroupMessage(sender, groupId, epoch, targets, payload, opts = {}, stateCommitment) {
28
+ const masterKey = new Uint8Array(randomBytes(32));
29
+ const msgNonce = new Uint8Array(randomBytes(12));
30
+ const messageId = opts.messageId ?? `m-${randomUUID().replace(/-/g, '')}`;
31
+ const timestamp = opts.timestamp ?? Date.now();
32
+ // wrap_protocol_str
33
+ const protocolSet = new Set();
34
+ for (const t of targets) {
35
+ const has3DH = !!t.spkPkDer &&
36
+ (t.keySource === 'peer_device_prekey' || t.keySource === 'group_device_prekey');
37
+ protocolSet.add(has3DH ? '3DH' : '1DH');
38
+ }
39
+ const wrapProtocolStr = protocolSet.size === 0 ? '1DH' : [...protocolSet].sort().join('+');
40
+ // state_commitment(缺省占位)
41
+ const sc = stateCommitment ?? {};
42
+ const stateCommitmentAAD = {
43
+ state_version: Number(sc.state_version ?? 0) || 0,
44
+ state_hash: String(sc.state_hash ?? ''),
45
+ state_chain: String(sc.state_chain ?? ''),
46
+ };
47
+ const aad = {
48
+ from: sender.aid,
49
+ from_device: sender.deviceId,
50
+ group_id: groupId,
51
+ epoch,
52
+ message_id: messageId,
53
+ timestamp,
54
+ suite: SUITE_NAME,
55
+ wrap_protocol: wrapProtocolStr,
56
+ state_commitment: stateCommitmentAAD,
57
+ };
58
+ const plaintextBytes = canonicalJson(payload);
59
+ const aadBytes = canonicalJson(aad);
60
+ const { ciphertext, tag } = aesGcmEncrypt(masterKey, msgNonce, plaintextBytes, aadBytes);
61
+ const [senderSessionPriv, senderSessionPubDer] = generateP256Keypair();
62
+ // wrap_salt = SHA256(canonical_aad || sender_session_pk_der || suite)[:16]
63
+ const wrapSalt = computeWrapSalt(aadBytes, senderSessionPubDer);
64
+ const recipientsRows = [];
65
+ for (const target of targets) {
66
+ recipientsRows.push(wrapForRecipient(target, masterKey, senderSessionPriv, sender.ikPriv, wrapSalt));
67
+ }
68
+ const sortedRows = sortRecipients(recipientsRows);
69
+ const digestHex = computeRecipientsDigest(sortedRows);
70
+ const digestBytes = Buffer.from(digestHex, 'hex');
71
+ const signInput = Buffer.concat([
72
+ Buffer.from(ciphertext),
73
+ Buffer.from(tag),
74
+ Buffer.from(aadBytes),
75
+ digestBytes,
76
+ ]);
77
+ const senderSig = ecdsaSignRaw(sender.ikPriv, new Uint8Array(signInput));
78
+ const certFpHash = createHash('sha256').update(Buffer.from(sender.ikPubDer)).digest('hex');
79
+ const certFp = `sha256:${certFpHash.substring(0, 16)}`;
80
+ const envelope = {
81
+ type: 'e2ee.group_encrypted',
82
+ version: 'v2',
83
+ suite: SUITE_NAME,
84
+ msg_type: 'original',
85
+ group_id: groupId,
86
+ epoch,
87
+ t_send: timestamp,
88
+ t_server: null,
89
+ nonce: Buffer.from(msgNonce).toString('base64'),
90
+ ciphertext: Buffer.from(ciphertext).toString('base64'),
91
+ tag: Buffer.from(tag).toString('base64'),
92
+ sender_signature: Buffer.from(senderSig).toString('base64'),
93
+ sender_cert_fingerprint: certFp,
94
+ sender_session_pk: Buffer.from(senderSessionPubDer).toString('base64'),
95
+ recipients_digest: digestHex,
96
+ recipients: sortedRows,
97
+ aad,
98
+ };
99
+ // protected_headers / context:HMAC 签名,不进 AAD。
100
+ // payload_type 自动注入 + value 转 string(与 Python _normalize_headers 对齐)
101
+ const normalizedHeaders = normalizeProtectedHeaders(opts.protectedHeaders, payload);
102
+ if (Object.keys(normalizedHeaders).length > 0) {
103
+ envelope.protected_headers = withMetadataAuth(normalizedHeaders, masterKey, PROTECTED_HEADERS_DOMAIN);
104
+ }
105
+ if (opts.context && typeof opts.context === 'object' && !Array.isArray(opts.context) && Object.keys(opts.context).length > 0) {
106
+ envelope.context = withMetadataAuth(opts.context, masterKey, PROTECTED_CONTEXT_DOMAIN);
107
+ }
108
+ return envelope;
109
+ }
110
+ function computeWrapSalt(aadBytes, senderSessionPubDer) {
111
+ const suiteBytes = TEXT.encode(SUITE_NAME);
112
+ const h = createHash('sha256');
113
+ h.update(Buffer.from(aadBytes));
114
+ h.update(Buffer.from(senderSessionPubDer));
115
+ h.update(Buffer.from(suiteBytes));
116
+ return new Uint8Array(h.digest()).subarray(0, 16);
117
+ }
118
+ function wrapForRecipient(target, masterKey, senderSessionPriv, senderMasterPriv, wrapSalt) {
119
+ const fpHash = createHash('sha256').update(Buffer.from(target.ikPkDer)).digest('hex');
120
+ const fp = `sha256:${fpHash.substring(0, 16)}`;
121
+ const wrapNonce = new Uint8Array(randomBytes(12));
122
+ let wrapKey;
123
+ if (target.spkPkDer &&
124
+ (target.keySource === 'peer_device_prekey' || target.keySource === 'group_device_prekey')) {
125
+ wrapKey = compute3DHWrap(senderSessionPriv, senderMasterPriv, target.ikPkDer, target.spkPkDer, wrapSalt);
126
+ }
127
+ else {
128
+ wrapKey = compute1DHWrap(senderSessionPriv, target.ikPkDer, wrapSalt);
129
+ }
130
+ const { ciphertext: wrappedCt, tag: wrappedTag } = aesGcmEncrypt(wrapKey, wrapNonce, masterKey, new Uint8Array(0));
131
+ const wrappedKey = Buffer.concat([Buffer.from(wrappedCt), Buffer.from(wrappedTag)]);
132
+ return [
133
+ target.aid,
134
+ target.deviceId,
135
+ target.role,
136
+ target.keySource,
137
+ fp,
138
+ target.spkId ?? '',
139
+ Buffer.from(wrapNonce).toString('base64'),
140
+ wrappedKey.toString('base64'),
141
+ ];
142
+ }
143
+ //# sourceMappingURL=encrypt-group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encrypt-group.js","sourceRoot":"","sources":["../../../src/v2/e2ee/encrypt-group.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * AUN E2EE V2: P2P 加密引擎
3
+ *
4
+ * 构造完整的 `e2ee.p2p_encrypted` envelope。纯计算,无 IO。
5
+ *
6
+ * 与 Python `aun_core.v2.e2ee.encrypt_p2p.encrypt_p2p_message` 对齐。
7
+ *
8
+ * 步骤:
9
+ * 1. 生成 master_key + msg_nonce
10
+ * 2. 构造 message_id / timestamp
11
+ * 3. 推导 peer_aid 与 wrap_protocol_str
12
+ * 4. 构造 AAD 并加密 payload
13
+ * 5. 生成 sender_session keypair
14
+ * 6. 计算 wrap_salt
15
+ * 7. 为每个 target wrap master_key
16
+ * 8. 排序 recipients + 计算 digest
17
+ * 9. 计算 sender_signature
18
+ * 10. 计算 sender_cert_fingerprint
19
+ * 11. 组装 envelope
20
+ */
21
+ import { type ProtectedHeadersInput } from '../../protected-headers.js';
22
+ import { Sender, TargetSet, EncryptOptions } from './types.js';
23
+ /**
24
+ * 构造完整的 V2 P2P 加密 envelope。
25
+ */
26
+ export declare function encryptP2PMessage(sender: Sender, targetSet: TargetSet, payload: Record<string, unknown>, opts?: EncryptOptions): Record<string, unknown>;
27
+ /**
28
+ * 规范化 protected_headers:value 转 string + 自动注入 payload_type。
29
+ * 与 Python `_normalize_headers` 对齐。
30
+ */
31
+ export declare function normalizeProtectedHeaders(headers: ProtectedHeadersInput, payload: Record<string, unknown>): Record<string, string>;