@agentunion/fastaun 0.2.20 → 0.3.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/CHANGELOG.md +46 -23
- package/_packed_docs/CHANGELOG.md +46 -23
- 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 +90 -39
- package/dist/auth.js +24 -7
- package/dist/auth.js.map +1 -1
- package/dist/client.d.ts +115 -166
- package/dist/client.js +2006 -3427
- 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.js +4 -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 +31 -10
- package/dist/seq-tracker.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 +41 -0
- package/dist/v2/session/keystore.js +103 -0
- package/dist/v2/session/keystore.js.map +1 -0
- package/dist/v2/session/session.d.ts +97 -0
- package/dist/v2/session/session.js +242 -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,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ECDH P-256 — AUN E2EE V2 协议要求所有 SDK 的 ECDH 输出字节级一致。
|
|
3
|
+
*
|
|
4
|
+
* 共享秘密为 P-256 曲线点乘后的 X 坐标(32 字节,big-endian)。
|
|
5
|
+
*
|
|
6
|
+
* 实现选型:
|
|
7
|
+
* - 使用 Node `crypto` 模块(非 WebCrypto,TS SDK 目标为 Node 环境)
|
|
8
|
+
* - `createECDH('prime256v1')` 计算 X 坐标
|
|
9
|
+
* - 公钥使用 DER SubjectPublicKeyInfo 编码(与 Python/Go SDK 对齐)
|
|
10
|
+
* - 通过 JWK 中转完成 DER ↔ 未压缩点(0x04 || X || Y)的转换
|
|
11
|
+
*/
|
|
12
|
+
import { createECDH, createPublicKey } from 'node:crypto';
|
|
13
|
+
/**
|
|
14
|
+
* 把 base64url 字符串解码为 32 字节大端序无前导零填充的字节数组。
|
|
15
|
+
* 解决 JWK x/y 可能因高位为 0 而被截短的问题。
|
|
16
|
+
*/
|
|
17
|
+
function b64uToFixed32(b64url) {
|
|
18
|
+
const buf = Buffer.from(b64url, 'base64url');
|
|
19
|
+
if (buf.length === 32)
|
|
20
|
+
return buf;
|
|
21
|
+
if (buf.length < 32) {
|
|
22
|
+
const padded = Buffer.alloc(32);
|
|
23
|
+
buf.copy(padded, 32 - buf.length);
|
|
24
|
+
return padded;
|
|
25
|
+
}
|
|
26
|
+
// 长度 > 32:去掉前导 0x00 填充
|
|
27
|
+
const start = buf.length - 32;
|
|
28
|
+
for (let i = 0; i < start; i++) {
|
|
29
|
+
if (buf[i] !== 0) {
|
|
30
|
+
throw new Error(`invalid EC coordinate: length=${buf.length}, leading non-zero byte`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return buf.subarray(start, buf.length);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 把未压缩点(0x04 || X(32) || Y(32))的 X/Y 坐标转换为 SPKI DER 公钥。
|
|
37
|
+
*/
|
|
38
|
+
function uncompressedPointToDer(uncompressed) {
|
|
39
|
+
if (uncompressed.length !== 65 || uncompressed[0] !== 0x04) {
|
|
40
|
+
throw new Error('invalid uncompressed P-256 point');
|
|
41
|
+
}
|
|
42
|
+
const x = uncompressed.subarray(1, 33);
|
|
43
|
+
const y = uncompressed.subarray(33, 65);
|
|
44
|
+
const pubKey = createPublicKey({
|
|
45
|
+
key: {
|
|
46
|
+
kty: 'EC',
|
|
47
|
+
crv: 'P-256',
|
|
48
|
+
x: x.toString('base64url'),
|
|
49
|
+
y: y.toString('base64url'),
|
|
50
|
+
},
|
|
51
|
+
format: 'jwk',
|
|
52
|
+
});
|
|
53
|
+
return pubKey.export({ format: 'der', type: 'spki' });
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 计算 ECDH 共享秘密(P-256 X 坐标,32 字节)。
|
|
57
|
+
*
|
|
58
|
+
* @param privateKeyScalar 32 字节 P-256 私钥标量(big-endian)
|
|
59
|
+
* @param peerPublicKeyDer DER SubjectPublicKeyInfo 编码的对端公钥
|
|
60
|
+
* @returns 32 字节共享秘密(X 坐标 big-endian)
|
|
61
|
+
*/
|
|
62
|
+
export function ecdhComputeShared(privateKeyScalar, peerPublicKeyDer) {
|
|
63
|
+
if (privateKeyScalar.length !== 32) {
|
|
64
|
+
throw new Error(`expected 32-byte P-256 private scalar, got ${privateKeyScalar.length}`);
|
|
65
|
+
}
|
|
66
|
+
const ecdh = createECDH('prime256v1');
|
|
67
|
+
ecdh.setPrivateKey(Buffer.from(privateKeyScalar));
|
|
68
|
+
// 解析 DER SPKI 公钥 → 提取未压缩点(0x04 || X || Y)
|
|
69
|
+
const peerPubKey = createPublicKey({
|
|
70
|
+
key: Buffer.from(peerPublicKeyDer),
|
|
71
|
+
format: 'der',
|
|
72
|
+
type: 'spki',
|
|
73
|
+
});
|
|
74
|
+
const jwk = peerPubKey.export({ format: 'jwk' });
|
|
75
|
+
if (jwk.kty !== 'EC' || jwk.crv !== 'P-256' || !jwk.x || !jwk.y) {
|
|
76
|
+
throw new Error('peer public key is not a P-256 EC key');
|
|
77
|
+
}
|
|
78
|
+
const x = b64uToFixed32(jwk.x);
|
|
79
|
+
const y = b64uToFixed32(jwk.y);
|
|
80
|
+
const uncompressed = Buffer.concat([Buffer.from([0x04]), x, y]);
|
|
81
|
+
// ECDH.computeSecret 默认返回 X 坐标(32 字节大端序)
|
|
82
|
+
const shared = ecdh.computeSecret(uncompressed);
|
|
83
|
+
return new Uint8Array(shared);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 生成 P-256 密钥对。
|
|
87
|
+
*
|
|
88
|
+
* @returns [privateKeyScalar 32B, publicKeyDer SPKI]
|
|
89
|
+
*/
|
|
90
|
+
export function generateP256Keypair() {
|
|
91
|
+
const ecdh = createECDH('prime256v1');
|
|
92
|
+
const pubUncompressed = ecdh.generateKeys();
|
|
93
|
+
const priv = ecdh.getPrivateKey();
|
|
94
|
+
// setPrivateKey/generateKeys 返回的 priv 可能少于 32 字节(高位为 0),左零填充
|
|
95
|
+
let privPadded;
|
|
96
|
+
if (priv.length === 32) {
|
|
97
|
+
privPadded = priv;
|
|
98
|
+
}
|
|
99
|
+
else if (priv.length < 32) {
|
|
100
|
+
privPadded = Buffer.alloc(32);
|
|
101
|
+
priv.copy(privPadded, 32 - priv.length);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
throw new Error(`unexpected P-256 private key length: ${priv.length}`);
|
|
105
|
+
}
|
|
106
|
+
const pubDer = uncompressedPointToDer(pubUncompressed);
|
|
107
|
+
return [new Uint8Array(privPadded), new Uint8Array(pubDer)];
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 从私钥标量导出公钥 DER(SPKI 编码)。
|
|
111
|
+
*/
|
|
112
|
+
export function privateToPublicDer(privateKeyScalar) {
|
|
113
|
+
if (privateKeyScalar.length !== 32) {
|
|
114
|
+
throw new Error(`expected 32-byte P-256 private scalar, got ${privateKeyScalar.length}`);
|
|
115
|
+
}
|
|
116
|
+
const ecdh = createECDH('prime256v1');
|
|
117
|
+
ecdh.setPrivateKey(Buffer.from(privateKeyScalar));
|
|
118
|
+
const pubUncompressed = ecdh.getPublicKey();
|
|
119
|
+
const pubDer = uncompressedPointToDer(pubUncompressed);
|
|
120
|
+
return new Uint8Array(pubDer);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=ecdh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecdh.js","sourceRoot":"","sources":["../../../src/v2/crypto/ecdh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUN E2EE V2: ECDSA-SHA256 RAW(RFC 6979 deterministic)
|
|
3
|
+
*
|
|
4
|
+
* 规范引用:§3.1
|
|
5
|
+
* - 曲线 P-256
|
|
6
|
+
* - RFC 6979 deterministic nonce(必须)
|
|
7
|
+
* - 输出 RAW 编码 r(32B)||s(32B)
|
|
8
|
+
*
|
|
9
|
+
* 实现选型:
|
|
10
|
+
* - 使用 @noble/curves/nist 提供 deterministic ECDSA
|
|
11
|
+
* - 公钥使用 DER SubjectPublicKeyInfo(与 Python/Go 对齐)
|
|
12
|
+
* 通过 Node createPublicKey 提取未压缩点(0x04||X||Y)后传给 noble
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* ECDSA-SHA256 签名(RFC 6979 deterministic),输出 RAW 编码 r||s(64 字节)。
|
|
16
|
+
*
|
|
17
|
+
* @param privateKeyScalar P-256 私钥标量(32 字节 big-endian)
|
|
18
|
+
* @param message 待签名消息原文
|
|
19
|
+
* @returns 64 字节签名
|
|
20
|
+
*/
|
|
21
|
+
export declare function ecdsaSignRaw(privateKeyScalar: Uint8Array, message: Uint8Array): Uint8Array;
|
|
22
|
+
/**
|
|
23
|
+
* ECDSA-SHA256 验签(RAW 64 字节签名)。
|
|
24
|
+
*/
|
|
25
|
+
export declare function ecdsaVerifyRaw(publicKeyDer: Uint8Array, signatureRaw: Uint8Array, message: Uint8Array): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* 仅用于本地校验:根据 P-256 私钥派生公钥的 DER SPKI 编码。
|
|
28
|
+
*/
|
|
29
|
+
export declare function privateScalarToPublicDer(privateKeyScalar: Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUN E2EE V2: ECDSA-SHA256 RAW(RFC 6979 deterministic)
|
|
3
|
+
*
|
|
4
|
+
* 规范引用:§3.1
|
|
5
|
+
* - 曲线 P-256
|
|
6
|
+
* - RFC 6979 deterministic nonce(必须)
|
|
7
|
+
* - 输出 RAW 编码 r(32B)||s(32B)
|
|
8
|
+
*
|
|
9
|
+
* 实现选型:
|
|
10
|
+
* - 使用 @noble/curves/nist 提供 deterministic ECDSA
|
|
11
|
+
* - 公钥使用 DER SubjectPublicKeyInfo(与 Python/Go 对齐)
|
|
12
|
+
* 通过 Node createPublicKey 提取未压缩点(0x04||X||Y)后传给 noble
|
|
13
|
+
*/
|
|
14
|
+
import { p256 } from '@noble/curves/nist.js';
|
|
15
|
+
import { createPublicKey } from 'node:crypto';
|
|
16
|
+
/**
|
|
17
|
+
* 把 base64url 字符串解码为 32 字节大端序无前导零填充的字节数组。
|
|
18
|
+
*/
|
|
19
|
+
function b64uToFixed32(b64url) {
|
|
20
|
+
const buf = Buffer.from(b64url, 'base64url');
|
|
21
|
+
if (buf.length === 32)
|
|
22
|
+
return buf;
|
|
23
|
+
if (buf.length < 32) {
|
|
24
|
+
const padded = Buffer.alloc(32);
|
|
25
|
+
buf.copy(padded, 32 - buf.length);
|
|
26
|
+
return padded;
|
|
27
|
+
}
|
|
28
|
+
const start = buf.length - 32;
|
|
29
|
+
for (let i = 0; i < start; i++) {
|
|
30
|
+
if (buf[i] !== 0) {
|
|
31
|
+
throw new Error(`invalid EC coordinate: length=${buf.length}, leading non-zero byte`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return buf.subarray(start, buf.length);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 从 DER SPKI 编码公钥提取未压缩点(0x04||X||Y),共 65 字节。
|
|
38
|
+
*/
|
|
39
|
+
function derSpkiToUncompressed(publicKeyDer) {
|
|
40
|
+
const pub = createPublicKey({
|
|
41
|
+
key: Buffer.from(publicKeyDer),
|
|
42
|
+
format: 'der',
|
|
43
|
+
type: 'spki',
|
|
44
|
+
});
|
|
45
|
+
const jwk = pub.export({ format: 'jwk' });
|
|
46
|
+
if (jwk.kty !== 'EC' || jwk.crv !== 'P-256' || !jwk.x || !jwk.y) {
|
|
47
|
+
throw new Error('public key is not a P-256 EC key');
|
|
48
|
+
}
|
|
49
|
+
const x = b64uToFixed32(jwk.x);
|
|
50
|
+
const y = b64uToFixed32(jwk.y);
|
|
51
|
+
return Buffer.concat([Buffer.from([0x04]), x, y]);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* ECDSA-SHA256 签名(RFC 6979 deterministic),输出 RAW 编码 r||s(64 字节)。
|
|
55
|
+
*
|
|
56
|
+
* @param privateKeyScalar P-256 私钥标量(32 字节 big-endian)
|
|
57
|
+
* @param message 待签名消息原文
|
|
58
|
+
* @returns 64 字节签名
|
|
59
|
+
*/
|
|
60
|
+
export function ecdsaSignRaw(privateKeyScalar, message) {
|
|
61
|
+
if (privateKeyScalar.length !== 32) {
|
|
62
|
+
throw new Error(`expected 32-byte P-256 private scalar, got ${privateKeyScalar.length}`);
|
|
63
|
+
}
|
|
64
|
+
// 显式 prehash=true(默认值),noble 会用 SHA-256 摘要。
|
|
65
|
+
// lowS=false 与 Python/Go SDK 行为对齐(不强制低 S)。
|
|
66
|
+
// format='compact' 是默认值,输出 64B = r||s。
|
|
67
|
+
const sig = p256.sign(message, privateKeyScalar, {
|
|
68
|
+
prehash: true,
|
|
69
|
+
lowS: false,
|
|
70
|
+
format: 'compact',
|
|
71
|
+
});
|
|
72
|
+
if (sig.length !== 64) {
|
|
73
|
+
throw new Error(`unexpected signature length: ${sig.length}`);
|
|
74
|
+
}
|
|
75
|
+
return sig;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* ECDSA-SHA256 验签(RAW 64 字节签名)。
|
|
79
|
+
*/
|
|
80
|
+
export function ecdsaVerifyRaw(publicKeyDer, signatureRaw, message) {
|
|
81
|
+
if (signatureRaw.length !== 64)
|
|
82
|
+
return false;
|
|
83
|
+
try {
|
|
84
|
+
const uncompressed = derSpkiToUncompressed(publicKeyDer);
|
|
85
|
+
return p256.verify(signatureRaw, message, uncompressed, {
|
|
86
|
+
prehash: true,
|
|
87
|
+
lowS: false,
|
|
88
|
+
format: 'compact',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 仅用于本地校验:根据 P-256 私钥派生公钥的 DER SPKI 编码。
|
|
97
|
+
*/
|
|
98
|
+
export function privateScalarToPublicDer(privateKeyScalar) {
|
|
99
|
+
if (privateKeyScalar.length !== 32) {
|
|
100
|
+
throw new Error(`expected 32-byte P-256 private scalar, got ${privateKeyScalar.length}`);
|
|
101
|
+
}
|
|
102
|
+
// noble 返回未压缩 65 字节
|
|
103
|
+
const uncompressed = p256.getPublicKey(privateKeyScalar, false);
|
|
104
|
+
if (uncompressed.length !== 65 || uncompressed[0] !== 0x04) {
|
|
105
|
+
throw new Error('failed to derive uncompressed P-256 public key');
|
|
106
|
+
}
|
|
107
|
+
const x = uncompressed.subarray(1, 33);
|
|
108
|
+
const y = uncompressed.subarray(33, 65);
|
|
109
|
+
const pubKey = createPublicKey({
|
|
110
|
+
key: {
|
|
111
|
+
kty: 'EC',
|
|
112
|
+
crv: 'P-256',
|
|
113
|
+
x: Buffer.from(x).toString('base64url'),
|
|
114
|
+
y: Buffer.from(y).toString('base64url'),
|
|
115
|
+
},
|
|
116
|
+
format: 'jwk',
|
|
117
|
+
});
|
|
118
|
+
return new Uint8Array(pubKey.export({ format: 'der', type: 'spki' }));
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=ecdsa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecdsa.js","sourceRoot":"","sources":["../../../src/v2/crypto/ecdsa.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUN E2EE V2: HKDF-SHA256(RFC 5869)
|
|
3
|
+
*
|
|
4
|
+
* 规范引用:用于 1DH/3DH wrap_key 派生(info 分别为 "AUN-V2-1DH" 和 "AUN-V2-3DH")。
|
|
5
|
+
*
|
|
6
|
+
* 实现选型:
|
|
7
|
+
* - Node `crypto` 模块 HMAC-SHA256
|
|
8
|
+
* - 空 salt 视为 32 字节零(HashLen)
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* HKDF-SHA256(RFC 5869)。
|
|
12
|
+
*
|
|
13
|
+
* @param ikm Input keying material
|
|
14
|
+
* @param salt Salt(可为空,空时按规范用 HashLen 字节零填充)
|
|
15
|
+
* @param info Optional context and application specific information
|
|
16
|
+
* @param length 期望输出字节长度(不能超过 255 * HashLen)
|
|
17
|
+
* @returns OKM(output keying material)
|
|
18
|
+
*/
|
|
19
|
+
export declare function hkdfSha256(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Uint8Array;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUN E2EE V2: HKDF-SHA256(RFC 5869)
|
|
3
|
+
*
|
|
4
|
+
* 规范引用:用于 1DH/3DH wrap_key 派生(info 分别为 "AUN-V2-1DH" 和 "AUN-V2-3DH")。
|
|
5
|
+
*
|
|
6
|
+
* 实现选型:
|
|
7
|
+
* - Node `crypto` 模块 HMAC-SHA256
|
|
8
|
+
* - 空 salt 视为 32 字节零(HashLen)
|
|
9
|
+
*/
|
|
10
|
+
import { createHmac } from 'node:crypto';
|
|
11
|
+
const HASH_LEN = 32; // SHA-256 输出长度
|
|
12
|
+
/**
|
|
13
|
+
* HKDF-SHA256(RFC 5869)。
|
|
14
|
+
*
|
|
15
|
+
* @param ikm Input keying material
|
|
16
|
+
* @param salt Salt(可为空,空时按规范用 HashLen 字节零填充)
|
|
17
|
+
* @param info Optional context and application specific information
|
|
18
|
+
* @param length 期望输出字节长度(不能超过 255 * HashLen)
|
|
19
|
+
* @returns OKM(output keying material)
|
|
20
|
+
*/
|
|
21
|
+
export function hkdfSha256(ikm, salt, info, length) {
|
|
22
|
+
if (length < 0 || length > 255 * HASH_LEN) {
|
|
23
|
+
throw new Error(`HKDF length out of range: ${length}`);
|
|
24
|
+
}
|
|
25
|
+
// RFC 5869 §2.2: salt 为空时使用 HashLen 字节零
|
|
26
|
+
const realSalt = salt.length === 0 ? new Uint8Array(HASH_LEN) : salt;
|
|
27
|
+
// Extract: PRK = HMAC-SHA256(salt, IKM)
|
|
28
|
+
const prk = createHmac('sha256', realSalt).update(ikm).digest();
|
|
29
|
+
// Expand: T(i) = HMAC-SHA256(PRK, T(i-1) || info || i)
|
|
30
|
+
const out = new Uint8Array(length);
|
|
31
|
+
let t = new Uint8Array(0);
|
|
32
|
+
let pos = 0;
|
|
33
|
+
let counter = 1;
|
|
34
|
+
while (pos < length) {
|
|
35
|
+
const hmac = createHmac('sha256', prk);
|
|
36
|
+
hmac.update(t);
|
|
37
|
+
hmac.update(info);
|
|
38
|
+
hmac.update(Uint8Array.of(counter));
|
|
39
|
+
t = hmac.digest();
|
|
40
|
+
const remaining = length - pos;
|
|
41
|
+
out.set(t.subarray(0, Math.min(remaining, t.length)), pos);
|
|
42
|
+
pos += t.length;
|
|
43
|
+
counter++;
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=hkdf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hkdf.js","sourceRoot":"","sources":["../../../src/v2/crypto/hkdf.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,QAAQ,GAAG,EAAE,CAAC,CAAC,eAAe;AAEpC;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CACxB,GAAe,EACf,IAAgB,EAChB,IAAgB,EAChB,MAAc;IAEd,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,GAAG,GAAG,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,6BAA6B,MAAM,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,wCAAwC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAErE,wCAAwC;IACxC,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;IAEhE,uDAAuD;IACvD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACnC,IAAI,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,OAAO,GAAG,GAAG,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QACpC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,SAAS,GAAG,MAAM,GAAG,GAAG,CAAC;QAC/B,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3D,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC;QAChB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { canonicalJson, canonicalStringify } from './canonical.js';
|
|
2
|
+
export { ecdhComputeShared, generateP256Keypair, privateToPublicDer } from './ecdh.js';
|
|
3
|
+
export { hkdfSha256 } from './hkdf.js';
|
|
4
|
+
export { aesGcmEncrypt, aesGcmDecrypt } from './aead.js';
|
|
5
|
+
export { ecdsaSignRaw, ecdsaVerifyRaw, privateScalarToPublicDer } from './ecdsa.js';
|
|
6
|
+
export { compute1DHWrap, compute3DHWrap, INFO_1DH, INFO_3DH, WRAP_KEY_LENGTH, } from './dh-path.js';
|
|
7
|
+
export { sortRecipients, computeLeafHash, computeMerkleRoot, computeMerkleProof, verifyMerkleProof, computeRecipientsDigest, } from './recipients.js';
|
|
8
|
+
export type { ProofStep } from './recipients.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { canonicalJson, canonicalStringify } from './canonical.js';
|
|
2
|
+
export { ecdhComputeShared, generateP256Keypair, privateToPublicDer } from './ecdh.js';
|
|
3
|
+
export { hkdfSha256 } from './hkdf.js';
|
|
4
|
+
export { aesGcmEncrypt, aesGcmDecrypt } from './aead.js';
|
|
5
|
+
export { ecdsaSignRaw, ecdsaVerifyRaw, privateScalarToPublicDer } from './ecdsa.js';
|
|
6
|
+
export { compute1DHWrap, compute3DHWrap, INFO_1DH, INFO_3DH, WRAP_KEY_LENGTH, } from './dh-path.js';
|
|
7
|
+
export { sortRecipients, computeLeafHash, computeMerkleRoot, computeMerkleProof, verifyMerkleProof, computeRecipientsDigest, } from './recipients.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/v2/crypto/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACpF,OAAO,EACL,cAAc,EACd,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC"}
|
|
@@ -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;
|