WiFi 数据加密的形式
本文在于阐述我对 WiFi 网络中各站点之间加密方式的理解。
提问
此前,我有过这样一个疑惑:
wifi 的数据传输形式为广播,那么考虑一下,当 A 站发送数据给 B 站时
- 如果 A 站和 B 站之间信号不直接可达,那么数据将会先由 A 站流往 AP(接入点/基站/路由器),再由 AP 流往 B 站,即靠 AP 做转发
- 如果 A 站和 B 站之间信号直接可达,数据广播出去后,AP 和 B 站都会收到这个数据,那么 B 站是直接接受还是抛弃?又由于 AP 并不知道 B 站是否已经接收,所以会坚持转发一次,如果 B 站直接接受了,岂不是会导致数据无条件重发?
在理解了 wifi 的数据加密形式后,疑惑也被顺便解开了。
PS:说 wifi 其实不严谨,802.11 会更规范一点,不过为了方便理解,直接说 wifi 也无妨,因为不少读者可能不熟悉 802.11 和 wifi 的关系。
共识
行文开始前先做一些概念约束以及一些我的个人观点。
模式限定
探讨范围限定在 AP 模式,也就是最流行的 wifi 接入模式,不涉及 Ad-hoc 模式,简要的描述就是:
- 有一个无线设备工作在 AP 模式,承担基站的角色(路由器)
- 其他所有的设备全部和基站建立无线链路(手机、平板、笔记本……接入 wifi)
- 所有站点之间的数据通信均通过基站进行转发,类似于 C/S 模式
- 只要基站挂掉,所有站点之间将无法互相通信
通信数据安全
一般而言,通信数据的加密手段不同于数据存储。对于数据存储,通常采用对称加密,且只用一把密钥;而通信数据的做法大致是这样的:
- 通信双方共享一把长期的主密钥 K
- 通信双方基于 K 做一次安全握手,派生出一把当前会话使用的密钥 k
- 接下来的通信均使用 k 加密
- 每隔一定时间,双方重新派生出一把新的会话密钥 k2,替换 k,继续后续通信
这样做的好处有两点:
- 密钥分离:会话密钥 k 即便泄露也不会牵连主密钥 K,反过来主密钥被攻破之前的历史会话也不会因为一把 k 的泄露而全军覆没
- 密钥新鲜度:同一把密钥加密的样本越多,越有利于密码分析。即便算法本身没被破,定期轮换密钥也能提高整体的安全性
广播报文与广播链路
在广播式链路上发送广播报文具有得天独厚的优势:
- 古老的集线器也是广播式链路,某站点要发送一个广播报文,集线器不需要任何处理,只需要把广播报文当成普通报文广播即可
- 交换机将集线器的广播式链路改成了点对点链路,某站点要发送一个广播报文,交换机只能将该报文从每一个端口发送一次
- wifi 使用无线电通讯,自然也是广播链路,因此,某站点要发送一个广播报文,AP 只需要发送一次数据即可,无需将广播报文挨个站点发送一次
流程
大致流程如下(忽略广播):
- AP 和站点之间共享相同的初始密钥 PMK(Pairwise Master Key),关于 PMK 的来源后文会给出
- 每当有站点请求接入 AP,AP 和站点之间就会通过 PMK 生成出一把正式传输数据用到的密钥 PTK(Pairwise Transient Key)
- AP 和站点之间的通讯全部使用 PTK 加密
如果稍加留意,你会发现,每个站点和 AP 之间都维护着一个 PTK,但是站点和站点之间是不共享 PTK 的,站点 A 和 AP 之间的通讯使用 PTKa,站点 B 和 AP 之间的通讯使用 PTKb。
因此,站点 A 是没有能力和站点 B 直接通讯的,必须经由 AP 做数据转发,也就是说,即使站点 B 接收到了站点 A 发出的帧中白纸黑字写着”接收方为站点 B”,站点 B 也不得不抛弃,因为帧中的载荷数据是使用 PTKa 加密的,而站点 B 并不知道 PTKa,只能等待 AP 解析此帧,并换用 PTKb 加密后重新发送一个新帧,站点 B 才可以看见来自站点 A 的数据。
换言之,PTK 的方式保证了站点和站点之间在链路上是 “隔离” 的,任何站点都无法嗅探到不是发送给它的数据。
接下来谈谈数据的广播,如果站点 A 需要发送 IP 广播,单借助 PTK,也是可以做到的:站点 A 将广播包发送给 AP,AP 再将广播包重新编码逐个发给所有接入的站点,但这种做法太愚蠢,现实的流程如下:
- AP 启动后生成一个随机初始密钥 GMK(Group Master Key)
- AP 使用 GMK 通过某种算法,衍生出一个用于加密广播/组播数据的密钥 GTK
- 每个接入 AP 的站点在得到了 PTK 后,AP 将 GTK 使用 PTK 加密后发送给站点
换言之,所有站点都持有相同的 GTK,那么站点发送 IP 广播的流程究竟是怎么样的呢?最容易想到的有两种。
第一种,站点直接通过 GTK 进行广播:
- 站点 A 使用 GTK 加密广播包并发送
- 站点 B 接收到从站点 A 发出的广播包
- 站点 C 离 A 较远,没能收到从站点 A 发出的广播包
- AP 收到了从站点 A 发出的广播包,然后做一次接力转发
- 所有站点接收到从 AP 转发的广播包
第二种,由 AP 通过 GTK 进行广播:
- 站点 A 使用 PTKa 加密广播包并发送
- AP 接收到从站点 A 发出的广播包
- AP 解码接收到的广播包,并使用 GTK 加密该广播包,再接力转发出去
- 所有站点接收到该 AP 转发的广播包
不难看出,第二种方式是最优的,因为模式简单且和单播方式统一,而且第一种方式会造成站点重复接收广播包。事实上也的确采用的第二种方式。所以,GTK 对于站点来说,只用于解密,对于 AP 来说,只用于加密。
总结:wifi 网络内的所有站点间的所有通信都必须交给 AP 转发,站点和站点之间不存在任何直接通信行为。
关于 PMK
PMK 是怎么来的呢?
简单的说,接入 wifi 时需要你填的那个密码被称之为 PSK(Pre-Shared Key),将 PSK 使用一套算法进行一次转换,就是所谓的 PMK 了。
当然,PMK 不仅仅可以通过 PSK 得到,如果 wifi 使用 802.1X 的企业级证书认证方式(民用 wifi 很少支持这种认证方式),那么,PMK 就是标准的非对称密钥生成的对称密钥。
关于 GMK
此前我认为:GMK 可能只是为了和 PMK 概念对称,实际使用中,感觉完全没有存在的必要,AP 每次都生成一个随机串作为 GTK 就可以了。
如今我认为:GMK 的存在是为了方便 GTK 的周期性轮换——比如有站点退出网络时,应当更换 GTK 让退出的站点无法继续解密后续的广播数据,由 GMK 经过派生算出新 GTK,比每次都重新生成随机串要更轻量、可控。GMK 是某个 AP 自己内部的事,并不在多个 AP 之间共享。