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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM