该文章是之前计算机网络课程的一个作业,所以排版是实验报告的形式。也只对P2P网络中使用到的技术的概念进行介绍,想看深入介绍的可以点“X”了。。。然后之前看关于Tox协议的介绍好像也不多,这篇简单了介绍了Qt + Tox的使用。
-
实验名称
使用Tox协议进行p2p聊天
-
实验目的
- 了解和使用Tox端到端加密及点对点即时通讯协议
- 了解NAT和UDP打洞
- 了解DHT
- 了解ECDH密钥交换算法
-
实验内容
创建一个tox实例,绑定回调函数
创建一个tox实例,绑定回调函数
使用Timer每1000ms调用一次tox主循环
处理好友请求,直接调用tox_friend_add_norequest()同意好友申请‘
处理好友发来消息,将消息添加到界面上
处理网络变化,将状态添加到界面上
处理好友状态变化,根据不同场景显示状态到界面上
界面上的发送按钮的点击事件处理函数,使用tox_friend_send_message()向好友发送消息
-
- NAT穿透:NAT是作为一种解决IPv4地址短缺以避免保留IP地址困难的方案而流行起来,NAT同样也带来一些问题,就比如两个NAT后的主机没办法直接连接。为了实现p2p就必须绕过NAT,Tox使用了相比TCP打洞更加可靠的UDP打洞,打洞过程:NAT A下有主机A服务,NAT B下有主机B服务,A服务通过NAT A给B服务发一个包,NAT A会记录下B服务发过来的包都转发给A服务,同理B服务通过NAT B向A服务发送一个包,NAT B会记录下A服务发过来的包都转发给B服务,此后A服务和B服务就可以通信了。
- DHT:在UDP打洞中,必要条件就是A得知道B使用的公网ip和端口,B也得知道A使用的公网ip和端口。而在DHT网络中,IP和UDP端口就被放在DHT节点路由表中。每一条路由信息由如下3部分组成:IP Address、UDP Port、Node ID。Tox DHT是基于Kademlia的,在Kademlia中,每个节点有一个唯一ID(Tox中为256bit长),节点之间的距离以两节点ID异或XOR计算度量,网络中每个节点可以看为二叉树中的节点。
Kademlia协议中,每个节点按照与自己的距离来切割节点网络树:被切割的子树称之为Bucket,每个Bucket以节点ID最长公共前缀划分,也就是说每个Bucket中的节点必然与本节点具有相同的最长公共前缀。
我们从0011节点看,与其他节点最长公共前缀有0,1,2,3四种(对应图中四个圈起来部分),根据距离的不同放入不同的K桶中(每个K桶容量有限,这个容量也被称为K值)。
Bucket0 |
11111 |
11110 |
1110 |
1101 |
1100 |
101 |
… |
Bucket1 |
0111 |
01101 |
01100 |
01011 |
0100 |
01010 |
… |
Bucket2 |
000 |
|
|
|
|
|
|
Bucket3 |
00101 |
00100 |
|
|
|
|
|
查询过程:假设ID为X的节点要查询ID为T的节点,先计算X到T的距离D = X xor T,然后根据这个距离D去对应的k桶取出一定数量的节点(如果数量不足,则向此距离D最近的几个K桶取),并向这些节点发出FIND_NODE操作,这些节点如果发现自己就是T,就会返回自己是最接近T的,否则计算自己与T的距离然后根据此距离查询自己对应K桶选取节点返回给X。X接收到返回给他的节点,对这些节点进行FIND_NODE操作,不断重复此过程直到找到X。理论上只要最多LogN步就可以找到任意一节点。
-
- 加密:密钥交换:X25519;流加密:Xsalsa20;验证:Poly1305
利用X25519密钥交换,A和B各自有一公钥密钥对,tox使用crypto_box_keypair生成的公钥密钥对(均为256bit),此公钥密钥对可以用来生成一个共享密钥。如,A的密钥和B的公钥可以生成一个共享密钥,且此共享密钥与A的公钥和B的密钥可以生成的共享密钥相同。此后我们利用这个共享密钥使用XSalsa20 流对称加密方法对数据加密。
使用密钥交换,就会出现中间人攻击的风险,如出现一个C,在A向B发送自己公钥的时候,C将其改成自己的公钥,在B向A发送自己公钥的时候,C也改成自己的公钥,这样C就可以监听和篡改AB之间的通信了。因此需要加入验证器去验证对方的身份,tox使用的sodium库使用的是Poly1305。Poly1305输入一个256bit密钥和消息,输出一个128bit标签,此标签就可用来对密钥和消息进行验证。使用crypto_box_easy时,会将此128bit标签放在密文前,这也是每次加密后,密文会比原文多16Byte(128bit)的原因。输入的密钥由AB的共享密钥和一随机数共同决定。
验证示例,key为密钥,out为标签
Sodium库中:
生成标签
验证
实验源代码及注解
不直接贴代码了,毕竟不是实验,放gitlab吧
https://gitlab.com/ithepug/toxwithqt