← API 文档
envelope signature bucket (hex) hkdf
Specification
INTD 数据包格式 v1
格式公开是有意为之:机密性和完整性来自对请求的加密和签名,而不是来自对布局的保密。固定结构和 CRC32 让服务器能在写入存储之前低成本地丢弃垃圾数据。
Stable Big-endian CRC-32/IEEE X25519 · HKDF · AES-256-GCM
容器
| 偏移 | 大小 | 字段 | 取值 |
|---|---|---|---|
| 0 | 4 | MAGIC | 0x49 0x4E 0x54 0x44(「INTD」) |
| 4 | 1 | VERSION | 0x01 |
| 5 | 1 | FLAGS | 0x00,保留 |
| 6 | 8 | TIMESTAMP | uint64 BE,unix 毫秒 —— 增量的基准 |
| 14 | 4 | EVENTS_COUNT | uint32 BE |
| 18 | 4 | BLOB_LENGTH | uint32 BE,EVENTS_BLOB 的长度 |
| 22 | N | EVENTS_BLOB | 连续排列的事件 |
| 22+N | 4 | CRC32 | uint32 BE,EVENTS_BLOB 的 CRC-32/IEEE |
总大小恰好为 26 + N 字节;多余字节视为错误。
事件
| 大小 | 字段 | 取值 |
|---|---|---|
| 1 | TYPE | 0x01 pageview,0x02 search |
| 4 | TS_DELTA | uint32 BE,TIMESTAMP 之后的毫秒数 |
| 2 + var | DOMAIN | uint16 长度 ≤ 255,UTF-8 |
| 2 + var | URL | uint16 长度 ≤ 2048,UTF-8 |
| 2 + var | QUERY | uint16 长度 ≤ 500,没有时为 0 |
| 1 + var | LANG | uint8 长度 ≤ 20,BCP 47 |
| 1 | DEVICE_TYPE | 0x00 unknown,0x01 desktop,0x02 mobile,0x03 tablet,0x04 bot |
字符串按 UTF-8 字符边界截断。若长度超出限制、字符串不是合法 UTF-8、事件数与头部不符,或 CRC32 不匹配,服务器将拒绝该数据包。
服务器会做什么
- 域名由 URL 重新计算(eTLD+1),不采用客户端提供的值。
- 从 URL 和查询中剥离令牌、密码、电子邮件和卡号。
- 丢弃超过 7 天的事件,以及来自未来(超过 10 分钟)的事件。
- 国家按连接 IP 解析,安装标识符针对每个扩展单独哈希。
加密与签名
sessionKey = random(32)
iv = random(12)
ciphertext = AES-256-GCM(sessionKey, iv, bucket)
ephemeral = X25519 —— 每个数据包一对新密钥
shared = X25519(ephemeral.private, extension.publicKey)
derivedKey = HKDF-SHA256(IKM = shared, salt = iv, info = "intentd-bucket-v1", 32)
encryptedKey = AES-256-GCM(derivedKey, iv, sessionKey) // 48 字节 X-Signature = hex(HMAC-SHA256(secret,
"intentd-v2|bucket|" + X-Timestamp + "|" + X-API-Key + "|" + hex(SHA-256(body)))) 该方案在扩展私钥日后遭泄露时不提供前向保密,也无法防范持有打包副本的人:针对重新打包的防护来自按安装划分的会话、扩展 ID 校验和服务端校验。
测试向量
// 一条 search 事件:基准 1758000000000,增量 7,
// 域名 a.io,URL https://a.io/?q=x,查询 x,语言 en,desktop
494e5444 01 00 0000019950f72c00 00000001 00000025
02 00000007 0004 612e696f 0011 68747470733a2f2f612e696f2f3f713d78 0001 78 02 656e 01
cee33ee2 HKDF-SHA256(IKM = 0x11 × 32, salt = 0x22 × 12, info = "intentd-bucket-v1", L = 32)
=> 4a359b8818fc073f6f81a3cb4acd9065302e285fbef0d35d2ff71fba107e6056