组密钥管理 Cluster(GroupKeyManagement)
Cluster ID: 0x003F |
所在 Endpoint: Endpoint 0(根端点)
GroupKeyManagement 负责管理 Matter 网络中用于组播(multicast)通信的加密密钥。 当你需要向一组设备同时发送命令(比如「关闭客厅所有灯」)时,设备之间需要共享一套对称密钥来加密和验证组播消息。 这个 Cluster 就是用来写入、读取、删除和维护这些密钥集的。
GroupKeyManagement 定义了一个 CacheAndSync(CS) Feature。
启用 CS 后,设备支持从 Distributed Compliance Ledger(DCL)缓存和同步信任的根证书,
并允许使用 CacheAndSync 安全策略。未启用 CS 的设备只能使用 TrustFirst 策略。
命令(Commands)
GroupKeyManagement Cluster 共有 4 个命令,用于管理密钥集(KeySet)的完整生命周期: 写入、读取、删除和列举。点击下方表格中的命令 ID 可跳转到对应的详细说明。
| ID | 名称 | 方向 | 说明 |
|---|---|---|---|
0x00 |
KeySetWrite | Client → Server | 写入或更新一个密钥集 |
0x01 |
KeySetRead | Client → Server | 读取指定密钥集的信息 |
0x03 |
KeySetRemove | Client → Server | 删除一个密钥集 |
0x04 |
KeySetReadAllIndices | Client → Server | 列出当前 Fabric 的所有密钥集 ID |
KeySetWrite -- 写入密钥集(0x00)
写入一个完整的密钥集(GroupKeySet)到设备中。如果指定的 GroupKeySetID 已存在,则更新它。 每个密钥集包含最多三个 Epoch 密钥,用于支持密钥轮换时的平滑过渡。
| 参数 | 类型 | 说明 |
|---|---|---|
| GroupKeySet | GroupKeySetStruct | 完整的密钥集结构体,包含 ID、安全策略和最多三组 Epoch 密钥 |
写入的 EpochKey 是敏感数据。设备在存储后不会回传明文密钥 ——
通过 KeySetRead 读取时,EpochKey 字段会返回 null,只能看到 EpochStartTime。
使用场景
Commissioner(如手机 App)在建立组播通信前,需要先通过 KeySetWrite 将共享密钥写入所有参与组播的设备。通常在设备配网成功后、加入组之前调用。
KeySetRead -- 读取密钥集(0x01)
读取指定 ID 的密钥集信息。返回 KeySetReadResponse, 其中包含密钥集的元数据(ID、安全策略、各 Epoch 起始时间),但不包含密钥明文。
| 参数 | 类型 | 说明 |
|---|---|---|
| GroupKeySetID | uint16 | 要读取的密钥集 ID |
KeySetReadResponse
| 字段 | 类型 | 说明 |
|---|---|---|
| GroupKeySet | GroupKeySetStruct | 密钥集信息(EpochKey 字段为 null,不返回明文) |
使用场景
管理端需要确认某个密钥集是否已成功写入、查看其安全策略和 Epoch 时间窗口时调用。 常用于密钥轮换前检查当前密钥集的状态。
KeySetRemove -- 删除密钥集(0x03)
删除指定 ID 的密钥集。删除前需要确保没有 GroupKeyMap 条目仍在引用该密钥集, 否则相关组将无法正常收发加密组播消息。
| 参数 | 类型 | 说明 |
|---|---|---|
| GroupKeySetID | uint16 | 要删除的密钥集 ID(不能为 0,ID 0 是 IPK 密钥集,不可删除) |
GroupKeySetID 为 0 的密钥集是 Identity Protection Key(IPK),
由 Fabric 建立时自动创建。尝试删除 ID 0 会返回 INVALID_COMMAND 错误。
使用场景
密钥轮换完成后,旧密钥集不再被任何组引用时,可以通过 KeySetRemove 清理掉,释放设备存储空间。
KeySetReadAllIndices -- 列举所有密钥集(0x04)
列出当前 Fabric 下所有已存储的密钥集 ID。返回 KeySetReadAllIndicesResponse。 不需要任何参数。
KeySetReadAllIndicesResponse
| 字段 | 类型 | 说明 |
|---|---|---|
| GroupKeySetIDs | list<uint16> | 当前 Fabric 拥有的所有密钥集 ID 列表 |
使用场景
管理端在执行密钥审计或轮换前,先调用此命令获取设备上所有密钥集的 ID, 再逐个通过 KeySetRead 查看详情,决定哪些需要更新或删除。
属性详解
GroupKeyManagement Cluster 共有 4 个应用属性。点击下方汇总表中的属性 ID 可跳转到对应的详细说明。
| ID | 名称 | 类型 | 可写 | 说明 |
|---|---|---|---|---|
0x0000 |
GroupKeyMap | list<GroupKeyMapStruct> | 是 | 组 ID 与密钥集的映射关系 |
0x0001 |
GroupTable | list<GroupTableStruct> | 否 | 设备上所有组的信息表 |
0x0002 |
MaxGroupsPerFabric | uint16 | 否 | 每个 Fabric 最多支持的组数量 |
0x0003 |
MaxGroupKeysPerFabric | uint16 | 否 | 每个 Fabric 最多支持的密钥集数量 |
GroupKeyMap -- 组密钥映射(0x0000)
这是本 Cluster 最核心的属性。它定义了「哪个组使用哪个密钥集」的映射关系。 每个条目将一个 GroupId 关联到一个 GroupKeySetID,设备根据这个映射来选择加解密组播消息所用的密钥。
可写属性 —— 管理端可以直接写入来建立或修改映射。 一个密钥集可以被多个组共享,也可以为每个组分配独立的密钥集。
GroupKeyMapStruct 结构
| 字段 | 类型 | 说明 |
|---|---|---|
| GroupId | group-id | 组 ID(对应 Groups Cluster 中注册的组) |
| GroupKeySetID | uint16 | 关联的密钥集 ID(必须是已通过 KeySetWrite 写入的) |
| FabricIndex | fabric-idx | 所属 Fabric 索引(自动填充,Fabric 隔离) |
GroupTable -- 组信息表(0x0001)
只读属性,展示设备上所有已注册组的详细信息。 这个表由设备根据 Groups Cluster 的操作和 GroupKeyMap 自动维护,不能直接写入。
GroupTableStruct 结构
| 字段 | 类型 | 说明 |
|---|---|---|
| GroupId | group-id | 组 ID |
| Endpoints | list<endpoint-no> | 该组包含的 Endpoint 列表 |
| GroupName | string | 组名称(最长 16 字节,可选) |
| FabricIndex | fabric-idx | 所属 Fabric 索引 |
MaxGroupsPerFabric -- 最大组数(0x0002)
只读属性,标识每个 Fabric 最多可以注册多少个组。 这是设备的硬件/固件限制,管理端在规划组播拓扑时需要参考这个值。
MaxGroupKeysPerFabric -- 最大密钥集数(0x0003)
只读属性,标识每个 Fabric 最多可以存储多少个密钥集。 包括 IPK(ID = 0)在内。如果值为 3,则除了 IPK 外还能存 2 个自定义密钥集。
在写入密钥集或添加组映射前,先读取 MaxGroupsPerFabric 和
MaxGroupKeysPerFabric 确认设备还有空间。
超出限制的写入操作会返回 RESOURCE_EXHAUSTED 错误。
数据结构
GroupKeySetStruct(密钥集结构体)
描述一个完整的组播密钥集。包含密钥集 ID、安全策略、以及最多三组 Epoch 密钥和对应的起始时间。 三个 Epoch 插槽用于支持密钥轮换 —— 设备可以同时持有旧密钥和新密钥,实现无缝切换。
| 字段 | 类型 | 说明 |
|---|---|---|
| GroupKeySetID | uint16 | 密钥集唯一标识。0 为 IPK(Identity Protection Key),由 Fabric 自动管理 |
| GroupKeySecurityPolicy | GroupKeySecurityPolicyEnum | 安全策略 —— TrustFirst 或 CacheAndSync |
| EpochKey0 | octstr (16 bytes) / null | 第一个 Epoch 密钥(128 位 AES 密钥)。读取时返回 null |
| EpochStartTime0 | epoch-us / null | EpochKey0 的生效时间(微秒级 UTC 时间戳) |
| EpochKey1 | octstr (16 bytes) / null | 第二个 Epoch 密钥。用于密钥轮换过渡期 |
| EpochStartTime1 | epoch-us / null | EpochKey1 的生效时间 |
| EpochKey2 | octstr (16 bytes) / null | 第三个 Epoch 密钥。完成轮换后的最终密钥 |
| EpochStartTime2 | epoch-us / null | EpochKey2 的生效时间 |
三个 Epoch 插槽按时间顺序排列:EpochStartTime0 < EpochStartTime1 < EpochStartTime2。 设备在当前时间到达对应的 EpochStartTime 后自动切换到新密钥。 在切换窗口期内,设备能同时用旧密钥解密收到的消息、用新密钥加密发出的消息, 保证组内设备逐步更新密钥时不会中断通信。
枚举类型
GroupKeySecurityPolicyEnum(安全策略)
定义密钥集使用的安全验证策略。决定设备如何验证组播消息的来源可信度。
只有设备的 FeatureMap 中启用了 CS 位后,
才能在 KeySetWrite 中使用 CacheAndSync 策略。
向不支持 CS 的设备写入 CacheAndSync 密钥集会返回 INVALID_COMMAND。
Feature 位图
GroupKeyManagement Cluster 通过 FeatureMap(0xFFFC)声明设备支持的高级能力:
示例数据
一个已配置两个组的设备上,GroupKeyManagement Cluster 的属性读取结果:
{
// --- GroupKeyMap(密钥映射表)---
"0x0000": [
{
"GroupId": 1,
"GroupKeySetID": 1,
"FabricIndex": 1
},
{
"GroupId": 2,
"GroupKeySetID": 1,
"FabricIndex": 1
}
],
// --- GroupTable(组信息表,只读)---
"0x0001": [
{
"GroupId": 1,
"Endpoints": [1, 2],
"GroupName": "客厅灯组",
"FabricIndex": 1
},
{
"GroupId": 2,
"Endpoints": [3],
"GroupName": "卧室灯组",
"FabricIndex": 1
}
],
// --- 容量限制 ---
"0x0002": 4, // MaxGroupsPerFabric = 4
"0x0003": 3 // MaxGroupKeysPerFabric = 3
}
GroupKeyMap 是唯一可写的属性 —— 通过写入它来绑定组和密钥集。 GroupTable 是只读的,由设备自动根据 Groups Cluster 和 GroupKeyMap 计算生成。 密钥集本身通过 KeySetWrite / KeySetRead 命令管理,不通过属性读写。
常见场景
场景 1:为一组设备建立组播密钥
当你需要让多个设备加入同一个组并支持组播通信时:
- 先读取目标设备的
MaxGroupKeysPerFabric (0x0003),确认还有密钥集配额 - 通过
KeySetWrite (0x00)向每个目标设备写入相同的密钥集(相同的 GroupKeySetID 和 EpochKey) - 在每个设备上写入
GroupKeyMap (0x0000)属性,将 GroupId 映射到刚写入的 GroupKeySetID - 通过 Groups Cluster 的 AddGroup 命令将设备加入对应的组
- 读取
GroupTable (0x0001)确认组信息和 Endpoint 映射正确 - 现在可以向该组发送组播命令了,所有成员设备都能用共享密钥解密和执行
场景 2:密钥轮换(Key Rotation)
定期更换组播密钥是安全最佳实践。Matter 的三 Epoch 机制让轮换可以无缝进行:
- 通过
KeySetReadAllIndices (0x04)列出当前所有密钥集 ID - 通过
KeySetRead (0x01)读取目标密钥集,检查当前的 Epoch 时间窗口 - 生成新的 128 位 AES 密钥作为下一个 Epoch 密钥
- 通过
KeySetWrite (0x00)更新密钥集 —— 保留当前活跃的 EpochKey,将新密钥写入下一个 Epoch 插槽,设置未来的 EpochStartTime - 依次向组内每个设备写入相同的更新后密钥集
- 等待所有设备都更新完毕后,新 EpochStartTime 到达时自动切换到新密钥
- 确认所有设备已切换后,可以移除不再使用的旧 Epoch 密钥(通过下一次 KeySetWrite 覆盖)
密钥轮换的关键是 先写入所有设备,再让新密钥生效。 如果部分设备还持有旧密钥而其他设备已切换到新密钥,这些设备之间的组播通信将中断。 因此建议将 EpochStartTime 设置到足够远的未来,确保所有设备都有时间完成更新。