webrtc中的dtls

简介

DTLS(Datagram Transport Layer Security) 是基于 UDP 场景下数据包可能丢失或重新排序的现实情况下,为 UDP 定制和改进的 TLS 协议。
在WebRTC 中使用 DTLS 的地方包括两部分: 协商和管理SRTP密钥和为DataChannel提供加密通道。

DTLS 协议由两层组成: Record 协议 和 Handshake 协议。

  • Record 协议: 使用对称密钥对传输数据进行加密,并使用 HMAC 对数据进行完整性校验,实现了数据的安全传输。
  • Handshake 协议:使用非对称加密算法,完成 Record 协议使用的对称密钥的协商。

基础知识 HMAC
HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code)的缩写.
HMAC背景: 为了确保接收方所接收到的报文数据的完整性,人们采用消息认证来验证上述性质。用来对消息进行认证的主要方式有以下3种:消息认证码、散列函数和消息加密。

  • 消息认证码:它是一个需要密钥的算法,可以对可变长度的消息进行认证,把输出的结果作为认证符。 ( 通过一段密钥加密)
  • 散列函数:它是将任意长度的消息映射成为定长的散列值的函数,以该散列值消息摘要)作为认证符。 ( 类似直接求hash)
  • 消息加密:它将整个消息的密文作为认证符 (使用算法,直接对文章加密)

HMAC是一种利用密码学中的散列函数来进行消息认证的一种机制,所能提供的消息认证包括两方面内容:

  • 消息完整性认证:能够证明消息内容在传送过程没有被修改
  • 信源身份认证:因为通信双方共享了认证的密钥,接收方能够认证发送该数据的信源与所宣称的一致,即能够可靠地确认接收的消息与发送的一致。

握手

webrtc抓包并分析

Client Hello

  • Epoch 0开始 , ChangeCipherSpec 后增 1

  • Sequence number, Epoch周期内递增,检查丢包和乱序

  • Version 协商使用的最高版本

  • Message Sequence 0 开始,每发送一个 handshake 消息增 1,重传的 handshake 消息中 message sequence 不变:

  • Fragment 防止udp 超过mtu分包

  • Random 客户端随机数

  • Session 会话id

  • Cookie udp防止被攻击新增

  • Cipher Suites 协商加密套件, 加密套件里包含(证书的类型、密钥生成算法、摘要算法等)。

    Cipher Suite 遵循 IANA 标准,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 的含义如下:
    Protocol:这里为 TLS 协议
    Key Exchange Algorithm:这里为 ECDHE 密钥交换算法
    Authentication Algorithm:这里为 ECDSA 算法,即服务端需要计算签名时(Certificate、ServerKeyExchange)使用的默认签名算法,此项可能为空(密钥交换算法为 RSA 时可能为空,为空时签名算法与密钥交换算法相同)
    Encryption Algorithm:这里为 AES_256_CBC 加密算法,即最终对称密钥加密使用的加密方式
    Hash Algorithm:这里为 sha1,即服务端需要计算摘要时(Certificate、ServerKeyExchange)使用的默认 hash 算法
    一个套件由 对称加密算法有,密钥交换算法有,摘要算法 组成。
    三种密钥交换算法详解(RSA& DHE& ECDHE)

  • Extensions

    • use_srtp RFC5764, srtp使用
    • supported_groups(elliptic_curves),RFC8422, 描述支持的 ECC 加密算法
    • signature_algorithms DTLS1.2 的扩展,指定使用的 Hash 和 Signature 算法
    • extended_master_secret RFC7627, 扩展 MasterSecret 的生成方式

Server Hello,Certificate, Server Key Exchange, Certificate Request, Server Hello Done

  • Server Hello 对Client Hello的协商应答
  • Certificate
    数字证书,数字证书是由一些公认可信的证书颁发机构签发的,不易伪造。数字证书可以用于接收者验证对端的身份,接收者收到某个对端的证书时,会对签名颁发机构的数字签名进行检查,一般来说,接收者事先就会预先安装很多常用的签名颁发机构的证书(含有公开密钥),利用预先的公开密钥可以对签名进行验证。
    Server 端通过 Hello 消息,协商交换密钥的方法后,将 Server 证书发送给 Client,用于 Client 对 Server 的身份进行校验。Server 发送的证书必须适用于协商的 KeyExchange 使用的加密套接字,以及 Hello 消息扩展中描述的 Hash/Signature 算法对。
    在 WebRTC 中,通信的双方通常将无法获得由知名根证书颁发机构 (CA) 签名的身份验证证书,自签名证书通常是唯一的选择。RFC4572 定义一种机制,通过在 SDP 中增加自签名证书的安全哈希,称为 " 证书指纹 ",在保证 SDP 安全传输的前提下,如果提供的证书的指纹与 SDP 中的指纹匹配,则可以信任自签名证书。在实际的应用场景中,SDP 在安全的信令通道 (https) 完成交换的,SDP 的安全完整是可以做到的。这样在 DTLS 协商过程中,可以使用证书的指纹,完成通信双方的身份校验。证书指纹在 SDP 中的描述如下,参考 SDP-Anatomy 中 DTLS 参数。
a=fingerprint:sha-256 49:66:12:17:0D:1C:91:AE:57:4C:C6:36:DD:D5:97:D2:7D:62:C9:9A:7F:B9:A3:F4:70:03:E7:43:91:73:23:5E
  • Server Key Exchange
    ServerKeyExchange 用来将 Server 端使用的公钥,发送给 Client 端。分为两种情况:
  1. RSA 算法: 如果服务端使用的是 RSA 算法,可以不发送这个消息,因为 RSA 算法使用的公钥已经在 Certificate 中描述。
  2. DH 算法,是根据对方的公钥和自己私钥计算共享密钥。因为 Client 和 Server 都只知道自己的私钥,和对方的公钥;而他们的私钥都不同,根据特殊的数学特性,他们能计算出同样的共享密钥。关于 DH 算法如何计算出共享密钥,参考 DH算法。
    密钥交换的步骤
  • Certificate Request
    证书请求

  • Server Hello Done

Certificate, Client Key Exchange , Certificate Verify, Change Cipher Spec, Encrypted Handshake Message

  • Certificate 客户端证书

  • Client Key Exchange 完成密钥交换

  • Certificate Verify
    此消息是对客户端发送 CertificateVerify 之前所有收到和发送的握手信息(从 ClientHello 开始,不包括 ClientHello && HelloVerifyRequest 消息对)做的摘要签名,用于向服务端证明自己拥有 ClientKeyExchange 对应的私钥。
    客户端向服务器端证明自己是客户端证书的持有者。

  • Change Cipher Spec, Encrypted Handshake Message
    通过 ChangeCipherSpec 通知对端进入加密阶段,epoch 加 1。
    随后 Client 使用交换的密钥,对 "client finished" 加密,使用 Finished 消息,发送给服务端。Server 使用交换的密钥,对 "server finished" 进行加密发送给客户端。一旦验证了 finished 消息后,就可以正常通信了。

tls 加深理解之PreMaster secret、Master secret

PreMaster Secret

PreMaster Secret 是在客户端使用 RSA 或者 Diffie-Hellman 等加密算法生成的。它将用来跟服务端和客户端在 Hello 阶段产生的随机数结合在一起生成 Master Secret 。在客户端使用服务端的公钥对 PreMaster Secret 进行加密之后传送给服务端,服务端将使用私钥进行解密得到 PreMaster secret 。也就是说服务端和客户端都有一份相同的 PreMaster secret 和随机数。 premaster_secret 长度为 48 个字节,前 2 个字节是协议版本号,剩下的 46 个字节填充一个随机数。结构如下:

Struct {
byte Version[2];
byte random[46];
}

PreMaster secret 前两个字节是 TLS 的版本号,这是一个比较重要的用来核对握手数据的版本号,因为在 Client Hello 阶段,客户端会发送一份加密套件列表和当前支持的 SSL/TLS 的版本号给服务端,而且是使用明文传送的, 如果握手的数据包被破解之后,攻击者很有可能串改数据包,选择一个安全性较低的加密套件和版本给服务端,从而对数据进行破解。所以,服务端需要对密文中解密出来对的 PreMaster 版本号跟之前 Client Hello 阶段的版本号进行对比,如果版本号变低,则说明被串改,则立即停止发送任何消息。

Master secret

于服务端和客户端都有一份相同的 PreMaster secret 和随机数,这个随机数将作为后面产生 Master secret 的种子,结合 PreMaster secret ,客户端和服务端将计算出同样的 Master secret 。
Master secret 是有系列的 hash 值组成的,它将作为数据加解密相关的secret的 Key Material 的一部分。

简单来说,pre-master-secret由client产生,在产生该secret之前,client和server已经交换了client_random和server_random。然后client和server会使用一个PRF(Pseudo-Random Function)来产生master-secret。master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random)后续,client/server皆是通过该master_secret来产生对称加密的key,故client知道server端的key,server端也知道client端的key,为此能够发送/接收加密的信息。这里的key称为session key,包括6个部分:client_write_MAC_key, server_write_MAC_key, client_write_key, server_write_key, client_write_IV, server_write_IV。如果加密的方法使用stream cipher,则不需要client/server_write_IV。

tls形象的握手描述

我们假设A与B通信,A是SSL客户端,B是SSL服务器端,加密后的消息放在方括号[]里,以突出明文消息的区别。 双方的处理动作的说明用圆括号括起。
A: 我想和你安全的通话,我这里的对称加密算法有DES,RC5,密钥交换算法有RSA和DH,摘要算法有MD5和SHA
B: 我们用 DES-RSA-SHA 这对组合好了。这是我的证书,里面有我的名字和公钥,你拿去验证一下我的身份(把证书发给A)。目前没有别的可说的了。
A: (查看证书上B的名字是否无误,并通过手头早已有的 CA 的证书验证了B的证书的真实性,如果其中一项有误,发出警告并断开连接,这一步保证了B的公钥的真实性)(产生一份秘密消息,这份秘密消息处理后将用作加密密钥,加密初始化向量(IV)和hmac的密钥。将这份秘密消息-协议中称为 per_master_secret -用B的公钥加密,封装成称作 ClientKeyExchange 的消息。由于用了B的公钥,保证了第三方无法窃听)我生成了一份秘密消息,并用你的公钥加密了,给你(把 ClientKeyExchange 发给B)注意,下面我就要用加密的办法给你发消息了!(将秘密消息进行处理,生成加密密钥,加密初始化向量和hmac的密钥)[我说完了]
B:(用自己的私钥将 ClientKeyExchange 中的秘密消息解密出来,然后将秘密消息进行处理,生成加密密钥,加密初始化向量和hmac的密钥,这时双方已经安全的协商出一套加密办法了)注意,我也要开始用加密的办法给你发消息了![我说完了]
AB:加密通话

证书: 身份,说明谁是谁。 解决是谁的问题
密钥: 消息撞到箱子,有钥匙才能解开。 解决加密通道问题
签名: 消息是你提供的,而且没人改过。 解决消息有效性问题,防止发消息不认账。

posted on 2023-09-15 16:26  WillingCPP  阅读(309)  评论(0编辑  收藏  举报

导航