Tox 是一个开源的实时通信协议,不需要中央服务器,提供多种跨平台的客户端。
一个简单介绍: https://www.coldl.com/1545.html。
1、Tox 的基本用法
目前 Tox 提供多种跨平台的客户端,但基本用法都类似。
客户端可以直接生成新的账号,每个账号由公钥和私钥组成,其中公钥包含在用户 ID 中,私钥则保存在设备上。用户可以备份和复制私钥文件,然后用于不同设备登录相同账号。
账号可以用密码来保护,相当于将私钥用密码加密保存。但一旦忘记密码,账号就彻底丢失了。因为这里没有一个中心服务器提供找回密码的服务。
一个用户 ID 是由 32 字节的公钥, 4 字节的 NoSpam 码, 2 字节的校验码构成。其中一个字节实际数据为 0 到 255 ,用 16 进制的可视化表示( A 到 F 表示 10 到 15 )有 2 位。因此实际看到的是 64 位的公钥, 8 位的 NoSpam 码和 4 位的检验码:
这里 NoSpam 也是一个精妙的设计,可以防止恶意添加好友。由于公钥一旦公布就不能随意改动,如果没有 NoSpam ,相当于个人地址被泄露。现在用户可以通过修改 NoSpam 码,改动个人地址,对方必须使用新的地址才能添加好友。新地址有 256^4 种可能性,足以防范枚举攻击。而已有的好友关系不受影响。
添加好友后,聊天功能和其它工具类似。
2、Tox 的缺陷
目前 Tox 的主要缺陷有:
- 不支持离线消息。
- 实际使用时,用户状态不准确造就更大的问题。比如对方不在线却显示在线,或者明明已登录,对方却看不到我。在手机上尤其明显。
- 不支持多点登录。
- 点对点通讯,暴露个人位置。虽然可以通过代理来缓解,普通用户无能力也无资源。而且目前的 tox 实现,只支持匿名代理。但匿名代理很容易被滥用。
其中点对点通讯带来的问题在手机上尤其严重。即使不聊天,应用也需要和所有好友不断通讯维持用户的在线状态,每个好友都需要维持一个网络连接,这使得手机应用耗电非常大。
3、Tox 通信协议
Tox 使用一系列算法来确保加密,调用了NaCI
的实现libsodium
,所有实现都位于c-toxcore
。具体的规范在https://zetok.github.io/tox-spec/。
具体的加密算法有:
- (ECDSA & DH)密钥生成和交换算法: X25519
- (DEA)堆成加密算法: XSalsa20 stream cipher
- (MAC)验证: Poly1305 MAC
3.1、用户 ID 的生成
生成一个用户 ID 主要是要生成一个私钥-公钥对,具体实现使用NaCI
的crypto_box_keypair
函数。该函数内部使用的是 Curve25519 生成公钥和私钥密码对。
这里需要注意的是,该公钥私钥体系属于ECDSA,而不是 RSA 体系。它只能用来签名,不能用来加密解密。
用户 ID 除了公钥外,还有 4 位 NoSpam 码,这是完全随机的。检验码则是简单 XOR。
3.2、如何发现对方 IP
Tox 是点到点直连。那么在没有中心服务器存储每个人的位置时,如何获得对方的 IP 呢? 这可能是 Tox 最核心的部分了。这里面有两个最核心的组件:
- DHT 分布式哈希表。DHT 里有多个节点,每个 Tox 的客户端都是一个节点。每个节点都有一个临时 DHT 地址。DHT 网络的作用是:任何人都可以通过 DHT 查询指定节点。
- Onion 洋葱网络。洋葱网络连接
在这两个组件的帮助下,要想发现对方,只需要两步:
- 使用 Onion ,根据用户 ID 里面的公钥部分,查到好友的临时 DHT 地址。
- 使用 DHT ,连到指定 DHT 地址的具体节点。
由于 Onion 也构建在 DHT 的基础上,我们先看 DHT。
3.2.1、DHT 分布式哈希表
DHT 全称叫分布式哈希表(Distributed Hash Table),是一种分布式存储方法。在不需要服务器的情况下,每个节点负责一个小范围的路由,并负责存储一小部分数据,从而实现整个 DHT 网络的寻址和存储。
Tox 也使用 DHT 网络也维护所有用户的状态。每个用户的客户端都是 DHT 网络里的一个节点。每个节点都有一个临时的公钥私钥密码对,其中公钥作为节点(或者说用户)的临时 DHT 地址。这和用户 ID 非常类似,不同的时,用户 ID 在同一用户上保存不变,甚至可以通过复制转到另外一个客户端。而节点地址则在客户端每次重启都会重新生成。
TOX DHT 的维护算法基本和https://zh.wikipedia.org/zh-hans/Kademlia一致。每个节点都用8-buckets
结构维护临近节点。
当用户知道对方的 DHT 地址时,会递归查询与目标地址更近的节点,直到找到目标节点。tox 也提供 8 个引导节点,以实现第一层的递归查询。
3.2.2、Onion 洋葱网络
Onion 洋葱网络用来根据用户 ID 里面的公钥部分,查询用户的临时 DHT 地址。但它要实现的东西更多:
- 如果查询方已经是被查询方的好友,可以顺利查询到被查询方的好友。
- 如果查询方还不是被查询方的好友,此时不能暴露被查询方的位置。
- 不能从用户的临时 DHT 地址,暴露出该用户的公钥地址。
3.3、如何添加好友
【未完待续】
Q. E. D.