5.8 随机数负载 (Nonce Payload)
随机数(Nonce)负载在GDOI中用于提供新鲜性(freshness)和防止重放攻击。GDOI使用标准的ISAKMP随机数负载。
Nonce负载格式
Nonce负载使用标准的ISAKMP负载格式[RFC2408]:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload ! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
~ Nonce Data ~
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段说明:
- Next Payload: 下一个负载的类型
- Payload Length: 负载的总长度
- Nonce Data: 随机数数据
Nonce的用途
在GDOI中,Nonce负载用于:
在GROUPKEY-PULL中
Nonce提供新鲜性和密钥派生的输入:
第一条消息(组成员 -> GCKS)
HDR*, HASH(1), IDii, IDui, [CERT,] [CERTREQ,] SA, [KE,] [NONCE]
- 可选: 组成员可以 (MAY) 发送Nonce
- 新鲜性: 证明消息是最近生成的
- 密钥派生: 如果使用,Nonce参与密钥材料派生
第二条消息(GCKS -> 组成员)
HDR*, HASH(2), SA, [KE,] [NONCE,] [SEQ]
- 可选: GCKS可以 (MAY) 发送Nonce
- 响应绑定: 将响应绑定到特定的请求
- 密钥派生: 如果使用,Nonce参与密钥材料派生
与完美前向保密性(PFS)结合
当使用PFS时,Nonce和KE负载一起使用:
- KE负载: 提供Diffie-Hellman公钥
- Nonce负载: 提供额外的随机性
- 密钥派生: 两者结合派生KEK或用于KD负载保护的密钥
Nonce的生成
随机性要求
Nonce数据必须 (MUST) 是不可预测的:
- 高质量随机源: 使用密码学安全的伪随机数生成器(CSPRNG)
- 足够的熵: 确保有足够的熵源
- 避免重复: 每次生成新的、唯一的Nonce
长度要求
Nonce的长度:
- 最小长度: 应该 (SHOULD) 至少为128位(16字节)
- 推荐长度: 推荐 (RECOMMENDED) 使用256位(32字节)
- 可变长度: Nonce长度可以变化,但应在实现中保持一致
与HASH负载的关系
在GROUPKEY-PULL中,HASH负载的计算包括Nonce:
第一条消息的HASH(1)
HASH(1) = prf(SKEYID_a, M-ID | payload_1 | payload_2 | ... )
如果包含Nonce,它作为payload之一参与HASH计算。
第二条消息的HASH(2)
HASH(2) = prf(SKEYID_a, M-ID | Ni_b | payload_1 | payload_2 | ... )
其中Ni_b是第一条消息中的Nonce(如果有)。
密钥派生中的使用
当使用PFS时,Nonce参与密钥派生:
派生KEK保护密钥
KEYMAT = prf(SKEYID_d, g^xy | protocol | SPI | Ni | Nr)
其中:
g^xy: 从KE负载派生的Diffie-Hellman共享密钥protocol: 协议标识符SPI: 安全参数索引Ni: 发起方的NonceNr: 响应方的Nonce
派生的密钥材料用于保护密钥下载负载中的密钥。
处理规则
发送方规则
发送Nonce时:
- 生成随机数: 使用CSPRNG生成高质量的随机数据
- 设置长度: 使用足够的长度(至少128位)
- 唯一性: 确保每次交换使用新的Nonce
- 保存: 保存发送的Nonce用于后续的HASH或密钥派生
接收方规则
接收Nonce时:
- 提取数据: 从负载中提取Nonce数据
- 验证长度: 确保Nonce长度合理(不能太短)
- 保存: 保存接收的Nonce用于HASH验证或密钥派生
- 绑定: 将Nonce与特定的交换关联
与其他负载的关系
Nonce负载通常与以下负载协同使用:
HASH负载
- Nonce参与HASH计算
- 提供消息完整性和认证
KE负载
- 在PFS场景中一起使用
- 共同参与密钥派生
KD负载
- 派生的密钥用于保护KD负载中的密钥材料
安全考虑
Nonce的正确使用对安全性至关重要:
随机性
- 必须不可预测: Nonce必须 (MUST) 使用高质量的随机源
- 避免弱随机数: 弱随机数生成器会导致安全漏洞
- 足够的熵: 确保系统有足够的熵来源
新鲜性
- 防止重放: Nonce帮助防止重放攻击
- 唯一性: 每次交换使用新的Nonce
- 时效性: Nonce绑定消息到特定时间窗口
密钥派生
- 增强安全性: Nonce增加密钥派生的随机性
- 多方贡献: 发起方和响应方的Nonce都参与派生
- 前向保密: 与DH结合提供完美前向保密性
潜在威胁
如果Nonce不正确使用:
- 可预测Nonce: 允许攻击者预测或重放消息
- 重用Nonce: 可能导致密钥派生弱点
- 不足的长度: 增加碰撞和猜测的可能性
实现建议
随机数生成
使用操作系统提供的密码学安全随机数生成器:
- Linux:
/dev/urandom - Windows:
CryptGenRandom或BCryptGenRandom - OpenSSL:
RAND_bytes()
长度选择
- 默认: 使用256位(32字节)Nonce
- 兼容性: 确保与对等方的期望一致
- 性能: 更长的Nonce不会显著影响性能
存储
- 临时存储: Nonce只需在交换期间存储
- 安全清除: 使用后应安全清除Nonce
- 关联: 正确关联Nonce与特定的交换实例
示例
GROUPKEY-PULL with Nonces
组成员生成并发送:
Ni = random(32 bytes)
发送: HDR*, HASH(1), IDii, IDui, SA, KE, NONCE(Ni)
GCKS接收,生成并发送:
接收Ni
Nr = random(32 bytes)
发送: HDR*, HASH(2), SA, KE, NONCE(Nr), SEQ
双方派生密钥:
g^xy = DH(KE_i, KE_r)
KEYMAT = prf(SKEYID_d, g^xy | protocol | SPI | Ni | Nr)
使用KEYMAT保护KD负载
不使用Nonce的GROUPKEY-PULL
组成员发送:
发送: HDR*, HASH(1), IDii, IDui, SA
GCKS响应:
发送: HDR*, HASH(2), SA, KD, SEQ
不派生额外密钥:
KD负载直接使用第1阶段SA保护
第二种情况更简单但安全性略低,不提供PFS。