GWPK 包格式 v3:共用包 + 按设备包密钥包

固件升级包分两层。第一层是共用包:固件只加密一次,一份包文件, 所有设备共用。第二层是包密钥包:包密钥只包 32 字节,按设备各包一遍, 设备用自己的私钥解出包密钥,再解固件、验签。两层合起来,一份固件 只出一份包文件,不存 1000 个包文件;推送时也不现打整包,只现包 32 字节的密钥。

1. 共用包

包 = 312 字节包头 + 加密包体。包体是固件明文经 AES-256-GCM 加密 的结果,密钥是包密钥,随机数是包头里的包体随机数,附加认证数据 为空;密文后附 16 字节认证标签。所以包总长 = 312 + 明文长 + 16。

1.1 包头(312 字节,整数全小端)

偏移 长度 内容
0 4 魔数 GWPK(ASCII)
4 4 格式,u32,恒 3
8 100 型号,ASCII 零填充
108 100 固件名,ASCII 零填充
208 2 版本 major,u16
210 2 版本 minor,u16
212 2 版本 patch,u16
214 8 构建日期,ASCII YYYYMMDD
222 6 构建时间,ASCII HHMMSS(UTC,秒级)
228 4 明文长度,u32
232 4 标志,u32,恒 3
236 12 包体随机数(AES-256-GCM 随机数)
248 64 签名,Ed25519

字符串规则(型号、固件名):100 字节 ASCII 零填充,首个零字节后 必须全零,100 字节填满时须全 ASCII;空字段拒绝。型号只认 docs/models.md 注册表,当前唯一 stm32h743vi;固件名唯一 gateway。型号、固件名、版本、日期、时间只从签名包头或签名版本块 读,绝不从文件名解析;文件名只当人的标签。

标志:bit0 = 已加密,bit1 = 已签名,恒 3。其他位出现、或任一位 缺失,设备拒绝。

包文件命名:{固件名}-{完整型号}-release-v{版本}-{日期}-{时间}.pkg, 落在输入 bin 旁边;块型号 stm32h743vi 在文件名里拼完整订货型号 stm32h743vit6。解包默认输出为块生成名加 -out.bin。

1.2 签名

Ed25519,签名范围 = 包头 [0..248] + 固件明文(顺序拼接,签名本身 不参与)。型号、固件名、版本、日期、时间都在签名范围内,所以身份 字段有签名认证;改其中任一字节,验签失败。

签名密钥是云端签名密钥(全局一对,长久不动);每版签名值不同, 因为包内容不同。签名密钥轮换走备用机制(见第 4 节),不随版本变。

2. 包密钥包

包密钥包与共用包分开传输,80 字节,无魔数头,长度本身就是格式:

偏移 长度 内容
0 32 临时 X25519 公钥(每包 fresh,永不复用)
32 48 包装后包密钥 = 32 密文 + 16 标签

包装方法:临时 X25519 对每包 fresh;共享秘密 = 临时私钥 × 设备静态 公钥;包装密钥 = SHA-256(共享秘密);AES-256-GCM 加密包密钥,随机数 固定 12 字节零、附加认证数据为空。零随机数安全理由:包装密钥永不 重复(临时对每包 fresh,共享秘密永不重复)。

同一包密钥给同一设备包两次,结果不同(临时对不同),但两个包密钥包 都能解出同一包密钥。包密钥包损坏(标签错、长度错)在解包时安全拒绝, 不触碰包体。

3. 设备侧验证顺序

任一步失败即拒,绝不写备用区、绝不切换启动:

  1. 长度:包长 ≥ 312,且包体 = 明文长 + 16。
  2. 魔数、格式(只认 3)、标志(恒 3)。
  3. 型号、固件名合规且与本机一致。身份检查在解密前(签名仍覆盖身份, 身份无认证的问题不存在:第 7 步验签会覆盖身份字段)。
  4. 用本机私钥解包密钥包。标签错 → 设备密钥问题,拒。
  5. 解包体。标签错 → 包体问题,拒。第 4、5 步失败原因须分开上报。
  6. 解出长度 == 头明文长度。
  7. 验签:头 [0..248] + 明文,用云端签名公钥。
  8. 全过才写备用区、验完整性、切换启动;新版启动失败回滚旧版。

4. 密钥管理

5. 版本块与包格式版本

不要混淆两个版本号:固件 bin 偏移 0x1000 处的版本块是格式 2 (228 字节,FWVR 魔数,型号、固件名、版本、日期、时间,秒级), 见 docs/firmware-version-block.md;包格式是 v3(312 字节包头)。 包头身份字段来自版本块(版本唯一来源是固件的 Cargo.toml), 但包格式版本与版本块格式版本是两回事。更新规则:更新才装、 相等跳过、更旧拒绝。

6. 密钥与测试向量(仅测试,绝不量产)

测试覆盖:共用包往返逐字节一致;包密钥包往返(两次包装结果不同、 都能解出同一密钥);错设备密钥解包密钥包失败;包密钥包改一字节 (临时公钥区或包装区)失败;包密钥包长度错失败;改包体失败; 改签名区或身份字段失败;坏魔数、未知格式(2、1)、未知标志拒绝; 错验证公钥失败;包名与解包默认名按块生成。

7. 工具参数(按动作命名)