@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.
- package/CHANGELOG.md +63 -23
- package/_packed_docs/CHANGELOG.md +63 -23
- package/_packed_docs/design/2026-05-22-aun-rpc-trace-enhancement.md +542 -0
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1 -24
- 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
- package/_packed_docs/protocol/index.md +13 -3
- package/_packed_docs/python-sdk-v2-only-changelog.md +189 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +39 -16
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +131 -39
- package/_packed_docs/sdk/09-message-rpc-manual.md +30 -67
- package/dist/auth.js +26 -7
- package/dist/auth.js.map +1 -1
- package/dist/client.d.ts +117 -166
- package/dist/client.js +2130 -3419
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +0 -4
- package/dist/config.js +0 -4
- package/dist/config.js.map +1 -1
- package/dist/e2ee.d.ts +5 -139
- package/dist/e2ee.js +4 -1151
- package/dist/e2ee.js.map +1 -1
- package/dist/errors.d.ts +0 -8
- package/dist/errors.js +0 -14
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/keystore/aid-db.d.ts +12 -61
- package/dist/keystore/aid-db.js +41 -539
- package/dist/keystore/aid-db.js.map +1 -1
- package/dist/keystore/file.d.ts +5 -41
- package/dist/keystore/file.js +8 -64
- package/dist/keystore/file.js.map +1 -1
- package/dist/keystore/index.d.ts +1 -49
- package/dist/namespaces/auth.d.ts +8 -0
- package/dist/namespaces/auth.js +169 -2
- package/dist/namespaces/auth.js.map +1 -1
- package/dist/protected-headers.d.ts +13 -0
- package/dist/protected-headers.js +47 -0
- package/dist/protected-headers.js.map +1 -0
- package/dist/seq-tracker.d.ts +7 -2
- package/dist/seq-tracker.js +33 -13
- package/dist/seq-tracker.js.map +1 -1
- package/dist/transport.d.ts +11 -1
- package/dist/transport.js +255 -6
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +0 -56
- package/dist/v2/crypto/aead.d.ts +20 -0
- package/dist/v2/crypto/aead.js +59 -0
- package/dist/v2/crypto/aead.js.map +1 -0
- package/dist/v2/crypto/canonical.d.ts +20 -0
- package/dist/v2/crypto/canonical.js +119 -0
- package/dist/v2/crypto/canonical.js.map +1 -0
- package/dist/v2/crypto/dh-path.d.ts +39 -0
- package/dist/v2/crypto/dh-path.js +55 -0
- package/dist/v2/crypto/dh-path.js.map +1 -0
- package/dist/v2/crypto/ecdh.d.ts +29 -0
- package/dist/v2/crypto/ecdh.js +122 -0
- package/dist/v2/crypto/ecdh.js.map +1 -0
- package/dist/v2/crypto/ecdsa.d.ts +29 -0
- package/dist/v2/crypto/ecdsa.js +120 -0
- package/dist/v2/crypto/ecdsa.js.map +1 -0
- package/dist/v2/crypto/hkdf.d.ts +19 -0
- package/dist/v2/crypto/hkdf.js +47 -0
- package/dist/v2/crypto/hkdf.js.map +1 -0
- package/dist/v2/crypto/index.d.ts +8 -0
- package/dist/v2/crypto/index.js +8 -0
- package/dist/v2/crypto/index.js.map +1 -0
- package/dist/v2/crypto/recipients.d.ts +32 -0
- package/dist/v2/crypto/recipients.js +183 -0
- package/dist/v2/crypto/recipients.js.map +1 -0
- package/dist/v2/e2ee/decrypt.d.ts +29 -0
- package/dist/v2/e2ee/decrypt.js +159 -0
- package/dist/v2/e2ee/decrypt.js.map +1 -0
- package/dist/v2/e2ee/encrypt-group.d.ts +17 -0
- package/dist/v2/e2ee/encrypt-group.js +143 -0
- package/dist/v2/e2ee/encrypt-group.js.map +1 -0
- package/dist/v2/e2ee/encrypt-p2p.d.ts +31 -0
- package/dist/v2/e2ee/encrypt-p2p.js +190 -0
- package/dist/v2/e2ee/encrypt-p2p.js.map +1 -0
- package/dist/v2/e2ee/index.d.ts +9 -0
- package/dist/v2/e2ee/index.js +9 -0
- package/dist/v2/e2ee/index.js.map +1 -0
- package/dist/v2/e2ee/metadata-auth.d.ts +15 -0
- package/dist/v2/e2ee/metadata-auth.js +50 -0
- package/dist/v2/e2ee/metadata-auth.js.map +1 -0
- package/dist/v2/e2ee/types.d.ts +57 -0
- package/dist/v2/e2ee/types.js +7 -0
- package/dist/v2/e2ee/types.js.map +1 -0
- package/dist/v2/session/index.d.ts +4 -0
- package/dist/v2/session/index.js +3 -0
- package/dist/v2/session/index.js.map +1 -0
- package/dist/v2/session/keystore.d.ts +50 -0
- package/dist/v2/session/keystore.js +138 -0
- package/dist/v2/session/keystore.js.map +1 -0
- package/dist/v2/session/session.d.ts +124 -0
- package/dist/v2/session/session.js +318 -0
- package/dist/v2/session/session.js.map +1 -0
- package/dist/v2/state/commitment.d.ts +58 -0
- package/dist/v2/state/commitment.js +85 -0
- package/dist/v2/state/commitment.js.map +1 -0
- package/dist/v2/state/index.d.ts +2 -0
- package/dist/v2/state/index.js +2 -0
- package/dist/v2/state/index.js.map +1 -0
- 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>;
|