Skip to main content

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: 发起方的Nonce
  • Nr: 响应方的Nonce

派生的密钥材料用于保护密钥下载负载中的密钥。

处理规则

发送方规则

发送Nonce时:

  1. 生成随机数: 使用CSPRNG生成高质量的随机数据
  2. 设置长度: 使用足够的长度(至少128位)
  3. 唯一性: 确保每次交换使用新的Nonce
  4. 保存: 保存发送的Nonce用于后续的HASH或密钥派生

接收方规则

接收Nonce时:

  1. 提取数据: 从负载中提取Nonce数据
  2. 验证长度: 确保Nonce长度合理(不能太短)
  3. 保存: 保存接收的Nonce用于HASH验证或密钥派生
  4. 绑定: 将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: CryptGenRandomBCryptGenRandom
  • 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。