NFC 绑定¶
sim-hw 每次启动时都会生成 NFC 载荷,模拟嵌入在物理 Inklet 设备中的 NFC 标签。该载荷用于实现触碰配对的设备绑定。
NFC v2 载荷格式¶
| 参数 | 描述 |
|---|---|
v |
协议版本,固定为 2 |
kid |
工厂主密钥 ID |
hw |
设备硬件 UUID(32 位十六进制,无连字符) |
cv |
凭证版本号(吊销并重发后递增) |
p |
Base64url 编码的 128-bit truncated HMAC proof(16 字节) |
示例:
密钥派生与 proof 计算¶
NFC v2 采用一机一密方案:
deviceKey = HKDF-SHA256(masterKey[kid], salt=hwId, info="inklet:nfc-bind:v2")
proof = Truncate128(HMAC-SHA256(deviceKey, "v={v}&kid={kid}&hw={hw}&cv={cv}"))
- masterKey 存储在后端的 Secret Manager,永远不持久化、不记录、不传输到任何客户端。
- 每台设备的 deviceKey 由 masterKey 和该设备的 hwId 唯一派生,一台设备的密钥泄露不影响其他设备。
- proof 绑定了载荷的版本、keyId、hwId 和凭证版本,修改任意字段均会使 proof 失效。
v1 格式已废弃
旧版 inklet:1:{hwId}:{signature} 格式(基于单一 FACTORY_SECRET 的 HMAC truncated to 16 hex chars)已不再被后端接受。sim-hw 现在生成 NFC v2 URI 格式载荷。
载荷文件¶
sim-hw 每次启动时将 NFC 载荷写入 {data-dir}/nfc-payload。你可以读取此文件来模拟扫描设备的 NFC 标签。
cat devices/kitchen/nfc-payload
# inklet://bind?v=2&kid=k1&hw=a1b2c3d4e5f60708090a0b0c0d0e0f10&cv=1&p=AAAAAAAAAAAAAAAA
绑定流程¶
完整的 NFC 绑定流程如下:
物理设备 sim-hw 等效操作
──────────────── ─────────────────
设备上的 NFC 标签 → 数据目录中的 nfc-payload 文件
用户将手机触碰设备 → 用户从文件中复制 URI 载荷
App 读取 NFC 载荷 → 用户在 sim-dashboard 中粘贴载荷
App 解析 URI 参数 → sim-dashboard 解析 URI
App 调用 bind/nfc API → sim-dashboard 调用 bind/nfc API
后端验证 proof → 后端验证 proof(相同)
设备绑定到用户 → 设备绑定到用户(相同)
详细步骤:
-
App 读取 NFC --- 在现实中,移动应用读取 NFC 标签得到
inklet://bind?...URI。在模拟器中,你复制nfc-payload文件的内容。 -
App 调用 API --- 应用(或 sim-dashboard)解析 URI 参数并发送
POST /api/devices/bind/nfc请求: -
后端验证 --- 后端用 HKDF-SHA256 派生该设备的 deviceKey,重新计算 proof 并与提交的值常量时间比较。匹配则将设备绑定到当前认证用户,并返回
{"device": {...}, "status": "bound"}。 -
设备接收通知 --- 后端通过 MQTT 向设备发布
bound命令。sim-hw 收到后显示绑定确认信息。
安全注意事项¶
密钥管理
masterKey 由工厂控制台通过 KMS/Secret Manager 管理,不得出现在任何日志、响应或客户端代码中。sim-hw 在本地开发环境中使用 NFC_MASTER_KEYS 环境变量配置测试密钥。
- 一机一密:每台设备的 proof 是设备专属的,单台设备密钥泄露不影响其他设备。
- Proof 覆盖载荷完整性:
v、kid、hw、cv任何一个字段被篡改,proof 验证立即失败。 credentialVersion防重放:工厂吊销并重发后 cv 递增,旧版本 proof 立即失效。- Proof 长度 128 bit:在设备绑定场景下对在线猜测无实用边际,同时满足 NFC NDEF 记录的空间限制。
测试 NFC 绑定¶
使用 sim-hw 测试 NFC 绑定流程:
-
启动模拟设备:
-
读取 NFC 载荷:
-
在 sim-dashboard 中,点击"Bind Device",选择"NFC Payload"标签,粘贴载荷字符串。
-
或者,直接解析 URI 并调用 API:
-
设备应显示"Device bound successfully"并出现在你的仪表盘中。