GM/T 0128-2023 DTLCP 数据报传输层密码协议:国密 UDP 安全通信的协议架构与安全分析
概述
传输层密码协议(TLCP,GB/T 38636-2020)是面向 TCP 传输的国密安全协议,广泛用于金融、政务等场景的 HTTPS 国密改造。然而,在 UDP 环境下(如物联网、实时通信、QUIC 等),TLCP 的 TCP 依赖成为瓶颈。
GM/T 0128-2023《数据报传输层密码协议》(DTLCP)正是为解决这一问题而设计的协议。它在 TLCP 基础上添加了 UDP 适配机制:显式序列号、握手消息分段重组、无状态 Cookie、超时重传等,使国密安全通信能够运行在不可靠的数据报传输之上。
DTLCP 的核心设计哲学是「对 TLCP 改动最小化」——复用 TLCP 的密码套件、密钥派生、Finished 校验逻辑,在此基础上仅增加必要的 UDP 适配层。
协议分层架构
DTLCP 协议栈分为三层:
┌─────────────────────────────────────┐
│ Application Data │ 应用数据
├─────────────────────────────────────┤
│ ChangeCipherSpec (0x14) │ 密码规格变更
├─────────────────────────────────────┤
│ Handshake (0x16) │ 握手协议
├─────────────────────────────────────┤
│ Alert (0x15) │ 告警协议
├─────────────────────────────────────┤
│ Record Layer (13 字节头部) │ 记录层
└─────────────────────────────────────┘
↓ UDP 报文与 TLCP 的关键区别:
| 维度 | TLCP (TCP) | DTLCP (UDP) |
|---|---|---|
| 序列号 | 隐式 64 位计数器 | 显式 epoch + 48 位 sequence_number |
| 握手消息大小 | 无限制(TCP 流) | 必须支持分段重组(UDP MTU 限制) |
| DoS 防护 | 无 | HelloVerifyRequest + Cookie |
| 超时重传 | TCP 保证 | 四态状态机自行实现 |
| 记录头 | 5 字节 | 13 字节(增加 Epoch + SequenceNumber) |
记录层设计
记录头部结构
DTLCP 记录头总计 13 字节:
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Version | Epoch | SeqNum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number (续) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Fragment (变长) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+各字段说明:
| 字段 | 大小 | 说明 |
|---|---|---|
| Type | 1 字节 | 记录类型:握手(22)、密码规格变更(20)、告警(21)、应用数据(23) |
| Version | 2 字节 | 协议版本 {0x01, 0x01} |
| Epoch | 2 字节 | 密码规格变更计数器,区分密钥阶段 |
| SequenceNumber | 6 字节(48 位) | 显式序列号,同 epoch 内单调递增 |
| Length | 2 字节 | Fragment 长度 |
| Fragment | 变长 | 载荷数据 |
epoch 与 sequence_number 规则
- 每个 epoch 开始时 sequence_number 初始化为 0
- 每次发送记录时 sequence_number 单调递增
- 每次发送 ChangeCipherSpec 时 epoch 单调递增
- epoch/sequence_number 对必须唯一:在 2 倍 MSL(Maximum Segment Lifetime)时间内 epoch 值不能重用
- epoch 或 sequence_number 回绕前必须终止连接,重新握手
分片与重组
由于 UDP 报文受 MTU 限制(通常 1500 字节,扣除 IP/UDP 头部后约 1400 字节可用),DTLCP 握手消息必须支持显式分段和重组:
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| msg_type | length (3 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| message_seq | fragment_offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| fragment_length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| fragment_data... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+message_seq:消息序号,用于检测乱序和重复fragment_offset:当前分片在原始消息中的偏移量fragment_length:当前分片的长度
MAC 计算
CBC 模式:
MAC = HMAC_SM3(write_MAC_secret,
epoch + sequence_number + type + version + length + fragment)AEAD 模式(GCM):
additional_data = epoch + sequence_number + type + version + length注意:epoch 和 sequence_number 作为附加数据参与 MAC/AEAD 计算,这是 DTLS/DTLCP 与 TLS 的关键区别——TLS 中序列号是隐式的,不进入 MAC 计算。
握手协议
握手状态机
DTLCP 采用四态状态机管理握手过程:
| 状态 | 职责 |
|---|---|
| PREPARING | 构造本轮待发送的握手消息(Flight),缓存到发送队列 |
| SENDING | 将 Flight 的消息序列化并发送。若为最后一轮则转入 FINISHED,否则转入 WAITING |
| WAITING | 等待对端响应。三种退出:收到正确消息、超时重传、检测到对端重传 |
| FINISHED | 握手完成。保持 2×MSL 时间响应对端最后一个 Flight 的重传 |
- 重传定时器超时:WAITING → SENDING(重发 Flight,backoff 翻倍)
- 检测到对端重传:WAITING → SENDING(重发 Flight)
- 收到下一轮消息:WAITING → PREPARING
- 收到最后一轮消息:WAITING → FINISHED
- 发送完毕(最后一轮):SENDING → FINISHED
- FINISHED 收到重传:FINISHED → SENDING
message_seq 维护
每次握手的第一个消息 message_seq = 0,每产生一个新消息 message_seq 加 1。重传时使用相同的 message_seq。接收方维护 next_receive_seq 计数器:
message_seq == next_receive_seq→ 处理,计数器加 1message_seq < next_receive_seq→ 丢弃(重复)message_seq > next_receive_seq→ 排队缓存(乱序)
完整握手流程(6 个 Flight)
DTLCP 握手比 TLCP 多一个 Cookie 协商阶段,共 6 个 Flight:
| Flight | 发送方 | 消息 | Epoch |
|---|---|---|---|
| Flight 1 | Client | ClientHello(cookie=空) | 0 |
| Flight 2 | Server | HelloVerifyRequest(含 Cookie) | 0 |
| Flight 3 | Client | ClientHello(带 Cookie) | 0 |
| Flight 4 | Server | ServerHello + Certificate + ServerKeyExchange* + CertificateRequest* + ServerHelloDone | 0 |
| Flight 5 | Client | Certificate* + ClientKeyExchange + CertificateVerify* + [ChangeCipherSpec] + Finished | 0→1 |
| Flight 6 | Server | [ChangeCipherSpec] + Finished | 1 |
带 * 的消息为可选消息,取决于证书类型和密码套件选择。
Finished 校验数据
verify_data = PRF(master_secret, finished_label,
SM3(handshake_messages))[0..11]finished_label:客户端 "client finished",服务端 "server finished"handshake_messages:从 ClientHello 到本消息之前(不含本消息、CCS、HelloRequest)- 不包含:初始 ClientHello(如被替换)和 HelloVerifyRequest
handshake_messages 需要按 message_seq 排序后拼接,而非像 TLS 那样依赖 TCP 流的天然顺序。无状态 Cookie / DoS 防护
Cookie 生成
Cookie = HMAC_SM3(Secret, ClientAddr || ClientParams)Secret:Config.CookieSecret,服务端随机密钥,建议 ≥ 16 字节ClientAddr:客户端 UDP 地址(IP:Port,非仅 IP)ClientParams:ClientHello 关键字段序列化(version + random + sessionId + cipherSuites + compressionMethods)
Cookie 验证
服务端收到带 Cookie 的 ClientHello 后,用相同方式重新计算 expected,与收到的 Cookie 进行常数时间比较(防时序侧信道攻击)。
安全保证
| 攻击类型 | 防御效果 |
|---|---|
| 源 IP 伪造放大攻击 | 攻击者必须能接收 Cookie 响应才能继续握手 |
| 半连接资源耗尽 | Cookie 验证通过前服务端不分配任何连接状态 |
| Cookie 重放 | 服务端定期更换 Secret,旧 Cookie 过期失效 |
密钥层次结构
DTLCP 的密钥派生与 TLCP 保持一致:
预主密钥(48 字节)
↓ PRF + SM3
主密钥(48 字节)
↓ PRF + "key expansion" + server_random + client_random
├── client_write_MAC_secret(HMAC-SM3 密钥)
├── server_write_MAC_secret
├── client_write_key(SM4 加密密钥,16 字节)
├── server_write_key
├── client_write_IV(SM4-GCM 4 字节 / SM4-CBC 16 字节)
└── server_write_IV主密钥计算
master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)[0..47]SM4 密钥长度
| 算法 | key_material_length | fixed_iv_length |
|---|---|---|
| SM4-GCM | 16 字节 | 4 字节(IV 共 12 字节:4B 固定 + 8B 显式 nonce) |
| SM4-CBC | 16 字节 | 16 字节 |
密码套件
DTLCP 定义了以下密码套件:
| 密码套件 | 密钥交换 | 加密 | 校验 | 编码值 |
|---|---|---|---|---|
| ECC_SM4_GCM_SM3 | ECC | SM4-GCM | SM3 | {0xe0, 0x13} |
| ECC_SM4_CBC_SM3 | ECC | SM4-CBC | SM3 | {0xe0, 0x11} |
| ECDHE_SM4_GCM_SM3 | ECDHE | SM4-GCM | SM3 | {0xe0, 0x53} |
| ECDHE_SM4_CBC_SM3 | ECDHE | SM4-CBC | SM3 | {0xe0, 0x51} |
ECC 模式优先于 ECDHE:ECC 模式下服务端加密证书公钥固定,客户端直接使用公钥加密预主密钥,无需额外握手交互。
重传定时器
DTLCP 采用指数退避重传策略:
1s → 2s → 4s → 8s → 16s → 32s → 64s → 64s → ...调优建议:
| 网络环境 | InitialTimeout | MaxTimeout |
|---|---|---|
| 局域网(低延迟、低丢包) | 300ms ~ 500ms | 8s |
| 广域网(互联网) | 1s ~ 2s | 60s |
| 高丢包/卫星链路 | 500ms ~ 1s | 60s |
重放保护
DTLCP 采用滑动窗口机制进行重放检测:
- 最小窗口大小:32
- 默认窗口大小:64
- 窗口右边缘:当前会话接收到的最高有效序列号
- 窗口左边缘:右边缘 - 窗口大小
- 序列号 < 窗口左边缘 → 丢弃(重放)
- 序列号在窗口内且已记录 → 丢弃(重复)
- 序列号在窗口内且为新 → MAC 验证
- MAC 验证成功 → 更新窗口
PMTU 与路径最大传输单元
报文封装开销
以太网帧(≤ MTU 1500)
┌────────────────────────────────────────┐
│ L2 以太网帧头 14B MAC(6)+MAC(6)+Type(2) │
├────────────────────────────────────────┤
│ L3 IP 头部 20B │
├────────────────────────────────────────┤
│ L4 UDP 头部 8B │
├────────────────────────────────────────┤
│ DTLCP 记录头 13B [Type][Ver][Epoch] │
│ [SeqNum][Length] │
├────────────────────────────────────────┤
│ DTLCP 载荷(已加密/MAC) │
│ ≤ PMTU = 1400 B │
├────────────────────────────────────────┤
│ L2 以太网 FCS 4B │
└────────────────────────────────────────┘协议封装总开销:18(以太网) + 20(IP) + 8(UDP) + 13(DTLCP) = 59 B
默认 PMTU = 1400 推导:1500 - 59 - 41(余量) = 1400
三种场景
- 场景 A(记录 ≤ PMTU):一记录一报文
- 场景 B(记录 > PMTU):拆分为 N 个分片,fragment_offset + fragment_length
- 场景 C(多记录打包):同一 UDP 报文连续放置多条记录,总长度 ≤ PMTU
安全属性分析
机密性
DTLCP 使用 SM4-GCM 或 SM4-CBC + HMAC-SM3 提供数据机密性。GCM 模式作为 AEAD 算法,同时提供机密性和完整性;CBC 模式通过 Encrypt-then-MAC 方案实现等价安全强度。
完整性
所有记录均经过 SM3-HMAC 或 GCM AEAD 认证,攻击者无法在不被检测的情况下修改数据。
抗重放
通过 epoch + sequence_number 双重机制,配合滑动窗口检错,有效防止重放攻击。窗口大小可配置,默认 64。
DoS 防护
Cookie 机制确保服务端在握手完成前不分配任何连接状态,有效抵御 UDP 放大攻击和半连接耗尽攻击。
与 DTLS 1.2 的对比
| 维度 | DTLS 1.2 (RFC 6347) | DTLCP (GM/T 0128-2023) |
|---|---|---|
| 版本号 | {254, 253}(1's complement) | {0x01, 0x01} |
| 非对称算法 | RSA / ECDSA | SM2(ECC / ECDHE) |
| 分组密码 | AES (GCM/CBC) | SM4 (GCM/CBC) |
| 杂凑算法 | SHA-256 | SM3 |
| PRF | P_SHA256 | P_SM3(HMAC-SM3) |
| 签名算法 | RSA-SHA256, ECDSA-SHA256 | SM2WithSM3 (0x0704) |
| 双证书 | 不需要 | 需要(签名证书 + 加密证书) |
| 序列号 | 显式 epoch+seq(64 位) | 显式 epoch+seq(48 位) |
| 重放防护 | 滑动窗口(默认 64) | 滑动窗口(默认 64,最小 32) |
| 密码套件数 | 数十种 | 4 种(国密专用) |
- 双证书要求:DTLCP 要求服务端同时持有 SM2 签名证书和 SM2 加密证书,这是国密标准的强制性要求,与国际标准不同。
- 序列号长度:DTLS 1.2 使用 64 位序列号,DTLCP 使用 48 位序列号,这是因为国密场景下握手消息更少、连接生命周期更可控。
- 密码套件精简:DTLCP 仅定义 4 种密码套件,均为 SM2+SM4+SM3 组合,体现了国密标准的统一性要求。
相关实践
- DTLCP UDP 国密 TLS 实战指南 — DTLCP 工程部署完整指南
- GM/T 0129-2023 SSH 密码协议 — 基于 DTLCP 的 SSH 国密协议
- GM/T 0054-2018 密码应用基本要求 — DTLCP 合规要求
- SM2 椭圆曲线公钥密码算法 — DTLCP 使用的非对称算法
- SM3 密码杂凑算法 — DTLCP 使用的哈希算法
- SM4 分组密码算法 — DTLCP 使用的对称算法
参考标准
- GM/T 0128-2023《数据报传输层密码协议规范》(2023-12-04 发布,2024-06-01 实施)
- GB/T 38636-2020《信息安全技术 传输层密码协议》(TLCP)
- RFC 6347《Datagram Transport Layer Security Version 1.2》
- GB/T 32918《信息安全技术 SM2 椭圆曲线公钥密码算法》
- GB/T 32905《信息安全技术 SM3 密码杂凑算法》
- GB/T 32907《信息安全技术 SM4 分组密码算法》