感觉大多数讨论都没说到重点。
案例司法鉴定的效果是:A 的 iPhone 和 B 的 iPhone 进行了 AirDrop 之后,在 B 离开的情况下,从 A 的 iPhone 里还原出 B 的身份信息。原理是:iPhone 进行 AirDrop 之后会存日志,于是从 A 的日志里的信息还原 B 的身份信息。
只要删除日志,无论 AirDrop 本身是否安全,都不影响后续不再能找到 B 的身份证据。我不明白为什么 Apple 要让 iPhone 自动记录 AirDrop 的日志,其心可诛。
大多数讨论(我所见到的)都说的是 AirDrop 的设备发现过程不安全,散列函数啦、撞库啦云云,还有人建议加盐(这个案例里面加盐不会带来什么安全性),我感觉这不是重点,下面解释原因。
AirDrop 设备发现的核心通常建模为隐私求交(private set intersection, PSI)问题。首先解释一下 AirDrop 接收方的三种模式:关、接受任意设备、接受且仅接受联系人的设备。重点是第三种,“联系人”模式。考虑 iPhone B 准备用 AirDrop 共享一份文件,考虑 B 周围有数台 iPhone,那么每个 iPhone 都可能处于三种模式之一,此时 B 需要显示潜在的接收设备:
- 首先 B 广播自己正在考虑 AirDrop,此时周围的设备 A 需要决定自己是否应该显示在 B 的潜在接收方列表里;
- 如果 A 是“关”,只要不理会这个广播即可;
- 如果 A 是“任意”,则接收到这种广播就回复 A 本身的一些信息(足以完成文件传输即可);
- 如果 A 是“联系人”,则应该探究 B 是否是 A 的联系人列表里的人,再决定。
第三种情况里,A 和 B 计算“B 是否在 A 的联系人列表里”就建模成 PSI,也就是 B 的数据是自己的手机号(以及 Apple ID 等,但这里就理解为手机号就行了),A 的数据是自己的联系人列表,计算结果是 A 知道了这两个集合的交集。如果交集非空,则 A 同意自己被显示为候选接收方并发送一些信息以便后续 AirDrop 传输文件。注意,理论上来说可以用“判断交集是否是空”建模,这样交集非空的时候 A 不会知道 B 到底是通讯录里的哪个人;但实操上,如果交集非空,则通常 A 和 B 是认识的,而且 AirDrop 的时候也会传输 B 的设备名称给 A,所以建模为 PSI 无伤大雅。
AirDrop 的设备发现没有采用安全的 PSI,而是采用了纸糊的算法,简单来说是这样:在 B 准备发送 AirDrop 时,它广播自己的手机号的散列值,如果 A 是“联系人”模式,则 A 检查这个散列值是否与 A 的通讯录里任何数据的散列值一致,如果是,则 A 同意自己被显示为候选接收方。实际操作还要复杂一些,比如要加入 Apple 的签名,以及一开始广播的是短的散列值(不能达到抗碰撞的密码学安全性),如果匹配,再进一步用长的散列值(达到抗碰撞的密码学安全性)匹配,这样可以确保没有碰撞,从而不会误显示。为什么这样做?当然是因为这样:再高效的 PSI 也没有达到这个算法的效率。
很明显 A 在被发现的过程中(即使 A 是“任意”模式,即使后来 B 没有选择发送文件给 A)会看到 B 的手机号的散列值,然后 A 会在日志里保存这个数据,所以可以从 A 的日志里读取这个散列值,然后枚举所有的手机号去匹配、筛选 B 可能的手机号,中国大陆的手机号只有 10^10 个,对于国家机器来说这种程度的计算根本是洒洒水。
现在可以解释为什么我认为这个案例里面,PSI 的安全性不是重点,日志才是重点了。如果多方安全计算(multi-party computation, MPC;PSI 是一种多方安全计算)采用无擦除模型,即 MPC 里 A 的数据总是被保存起来,那么只要查看 A 的日志,就可以在 A 的视角重播整个计算过程,从而得到过去的数据。当然,如果 B 不是 A 的联系人,这自然不能发现 B 是谁,但如果 B 是 A 的联系人,那么从日志可以还原出 B 的身份——即使采用“交集是否为空”的 MPC,也会导致 B 手机号的范围从 10^10 大幅降低到 A 的联系人列表(虽然 A 的联系人列表可能已经变了,但我们假设无擦除,因此该模型允许得知 A 在任意时刻的联系人列表,况且 A 在被国家机器控制之前主动删减 B 的可能性真的不高)。
另外,解释一下为什么这个算法加盐没有意义:
- 如果每次交互的时候,每个手机号的盐是固定的,那么等于没加。有人可能会说这会导致国家机器不能自己计算任意手机号的散列,但这个论证不成立,因为可以随便找一台 iPhone 然后把所有手机号都纳入联系人列表,然后从这台 iPhone 里就可以拿出所有手机号的散列值。
- 如果每次交互的时候,B 随机选择一个字符串作为盐,那么这会导致周围的设备(A)大量耗电,因为此时 A 无法预先缓存自己通讯录里所有号码的散列值,每次发现过程都要重新遍历通讯录计算,这在现阶段是不可接受的损耗;此外,这样做也不会显著改变安全性,因为 A 必然是要知道盐的,否则没法计算自己通讯录里的散列值,根据日志的尿性,盐很可能会被记住,此时国家机器只要针对 A 那次的盐计算全部手机号(或者全部被怀疑的手机号)的散列值即可,这依然是洒洒水的计算量。
教训是什么?不要记住不该记住的东西。这个案例里面 AirDrop 的日志和设备发现协议导致了类似如下的场景:如果我在路上想和旁边的一个人(比如我的朋友)说话,那么在那个时刻所有在我旁边的人,都会永远记住我是谁。这听起来就很恐怖。