3. 设备身份标识与密钥生成
设备身份是信任链的起点。没有稳定、唯一、不可伪造的设备身份,后续的证书签发、双向认证、权限判定都无从谈起。本节围绕三个相互衔接的问题展开:设备用什么标识自己、密钥从哪里生成、密钥从产生到销毁如何管理。
一、设备唯一标识符设计
设备唯一标识符(Device ID)是设备在信任体系中的“名字”。它必须满足四个基本要求:全局唯一(不同设备不冲突)、持久稳定(重启、刷机、换网络后不变)、不可篡改(攻击者无法伪造或克隆)、可解析(后台能据此定位设备档案与策略)。
常见标识来源有三类。第一类是芯片厂商固化标识,如 SoC 唯一序列号、eFuse 中烧录的 ID,优点是天然唯一且难以修改,缺点是可能涉及供应链隐私,且部分芯片不对外开放读取。第二类是密码学标识,即用设备公钥的哈希值作为 Device ID,例如取 SHA-256 公钥摘要的前 16 字节,形式如 dev:9f3a…c21b。这种方式把“身份”与“密钥”绑定,密钥换则身份换,天然防克隆。第三类是业务分配标识,由平台在注册时下发 UUID 或带厂商前缀的序列号,灵活但依赖注册流程的可靠性。
工程上推荐组合标识:以密码学标识作为主键,辅以芯片 ID 和业务序列号作为属性字段。这样既保证唯一性与防伪性,又便于运维检索。标识符本身不是秘密,可以明文传输,其可信性由后续的密钥签名来保证——这一点常被误解,需要明确:Device ID 负责“区分”,密钥负责“证明”。
二、密钥对生成方式
设备密钥对通常采用非对称算法,如 ECC P-256 或 RSA-2048。生成位置决定了安全等级,主要有三种方式。
安全芯片生成(推荐):在 SE(Secure Element)或 TPM 内部生成密钥,私钥永不离开芯片,签名运算在芯片内完成,外部只能拿到公钥和签名结果。典型流程是:向芯片发送“生成密钥对”指令 → 芯片内部用真随机数发生器产生私钥 → 返回公钥句柄或公钥值 → 后续签名通过句柄调用。这种方式能抵抗物理提取和软件窃取,适合高价值设备。
TEE 生成(折中):在可信执行环境(如 ARM TrustZone)中生成并保存密钥,私钥受硬件隔离保护,但理论上仍存在于内存中,防护强度低于独立安全芯片。适合成本敏感、但需要一定安全等级的消费类设备。
软件生成(最低):在普通应用或操作系统中用密码库生成密钥,私钥以文件或密钥库形式存储。部署简单、成本低,但一旦系统被攻破,私钥即可被导出。仅建议用于测试或低风险场景。
无论哪种方式,都必须使用真随机数或高质量伪随机数作为熵源。密钥生成后应立即导出公钥,用于后续 CSR(证书签名请求)或注册请求。
三、密钥生命周期管理
密钥不是“生成一次用一辈子”。完整的生命周期包含五个阶段,每个阶段都有明确的操作与判断依据。
① 生成:在设备首次启动或产线阶段完成。关键检查点是熵源质量、算法参数(曲线/模长)、私钥是否可导出。若私钥可导出,应视为高风险并记录。
② 注册与激活:设备用私钥对注册请求签名,平台验证签名后签发设备证书,并将 Device ID 与公钥指纹写入设备档案。此时密钥进入“激活”状态,可用于业务认证。
③ 使用:私钥仅用于签名或解密,不用于加密传输密钥(除非协议明确要求)。每次使用应记录操作类型、时间、结果,便于审计。若发现异常签名频率或来源,应触发告警。
④ 轮换:当密钥达到有效期、算法面临淘汰、或怀疑泄露时,生成新密钥对并重新注册。轮换应支持平滑过渡:新旧密钥并存一段时间,平台同时接受两者签名,待设备全部切换后再吊销旧密钥。
⑤ 吊销与销毁:设备退役、丢失或确认泄露时,平台将证书加入 CRL 或 OCSP 吊销列表,设备端清除私钥存储区。销毁应确保不可恢复,安全芯片可执行“密钥擦除”指令。
四、实操示例:设备注册请求的构造与验证
以下示例展示设备端如何用安全芯片生成密钥并构造注册请求。假设设备已具备 SE 接口,算法选用 ECC P-256。
// 1. 在 SE 内生成密钥对,返回密钥句柄
keyHandle = se_generate_keypair(ALG_ECC_P256, KEY_USAGE_SIGN);
// 2. 导出公钥(仅公钥可导出)
pubKey = se_export_public_key(keyHandle); // 65 字节未压缩点
// 3. 计算 Device ID:SHA-256(公钥) 前 16 字节
deviceId = "dev:" + hex(SHA256(pubKey)[0..15]);
// 4. 构造注册载荷
payload = {
"device_id": deviceId,
"pub_key": base64(pubKey),
"alg": "ES256",
"nonce": random_16_bytes()
};
// 5. 用私钥签名(在 SE 内完成)
signature = se_sign(keyHandle, SHA256(payload));
// 6. 发送注册请求
POST /v1/devices/register
{ "payload": payload, "signature": base64(signature) }
平台侧收到请求后,按以下顺序验证:解析 payload 取出公钥 → 用公钥验证 signature 是否匹配 payload 的 SHA-256 → 重新计算 Device ID 并与 payload 中的 device_id 比对 → 检查 nonce 是否重复 → 通过后签发证书。任何一步失败都应拒绝注册并记录原因。