Qt + Tox协议的简单使用(简单P2P聊天程序实现)

该文章是之前计算机网络课程的一个作业,所以排版是实验报告的形式。也只对P2P网络中使用到的技术的概念进行介绍,想看深入介绍的可以点“X”了。。。然后之前看关于Tox协议的介绍好像也不多,这篇简单了介绍了Qt + Tox的使用。

  1. 实验名称

使用Tox协议进行p2p聊天

  1. 实验目的

    • 了解和使用Tox端到端加密及点对点即时通讯协议
    • 了解NAT和UDP打洞
    • 了解DHT
    • 了解ECDH密钥交换算法
  2. 实验内容

创建一个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

posted @ 2021-10-06 23:24  ithepug  阅读(738)  评论(0编辑  收藏  举报