以前看LumaQQ(2006版)時做的一點簡單記錄,主要是關于LumaQQ登陸服務器和通訊時數據包的加密和解密情況。
1.QQ的登陸
1.1. 登陸QQ服務器流程
啟動登陸程序,輸入QQ號碼和登陸密碼,選取登陸模式,進行網絡設置。登陸QQ。
現在做一個測試。將完全在登陸狀態下的LumaQQ打開調試窗口,并開始進行調試(點擊Start Debug 按鈕)。

選擇下線,然后再選擇上線。我們可以看到下面捕獲到的數據包。
當選擇離線時,發送了Logout Packet 包,此包并不需要服務器作出回應。再登陸的時候,QQ客戶端向服務器發送一個請求登錄令牌的數據包(請求登錄令牌包是不加密的),服務器接收到請求登錄令牌后返回請求登錄令牌的回復包給客戶端,這個請求登錄令牌的回復包是在服務器端生成的。在QQ客戶端得到登錄令牌回復包之后,就會向服務器發送一個登錄請求包(有資料聲稱:這個登錄包除了隨機密鑰本身以外的部分都要用隨機密鑰進行加密),要求登錄。服務器會驗證客戶端的登錄信息是否與服務器上保存的登錄信息匹配,返回一個登陸請求回復包。如果匹配就向客戶端返回登錄成功,不匹配返回登錄失敗。

登陸成功后,還附帶有些其他的數據請求包和回復包,這里暫不討論其他包。(注:Request Key Packet用來請求得到一些操作的密鑰,比如文件中轉,或者語音視頻之類的都有可能)
1.2.登陸信息保存到本地流程
在登陸數據從數據框輸入之后和登陸操作進行之前,程序就會把數據保存到本地的文件上。其中的數據主要包括QQ號碼,登陸密碼,登陸模式,網絡設置信息等等。
這里的登陸密碼保存方式會根據登陸模式的不同而采取不同的數據加密方案。
用戶從輸入框的密碼,系統取到原始密碼值時馬上進行兩次md5。保存到變量md5pwd,當保存密碼到本地時,如果是選擇記住密碼模式,則將md5pwd做一次base64再保存;如果是選擇是非記住密碼模式,則將md5pwd做一次base64之后再做一次md5,再來一次base64,最后在保存。
因為MD5的算法是不可逆的,沒有辦法直接解密。也沒有用到密鑰之類的東西。
2. QQ數據包的加密和解密
2.1. 數據包和密鑰
登錄數據包也是一個數據包,數據包在網絡傳輸時一般都會經過加密(除了數據包的頭部和尾部),登陸包是用初始密鑰,即一開始構造QQ客戶端對象時候生成的16位的十六進制的隨機數(這里稱作隨機密鑰吧),進行對登錄數據包加密。加密算法暫時跳過。
服務器接收到請求登陸包后作出反應,向客戶端發送一個請求登陸回復包,客戶端用上面提到的md5pwd(原始密碼的兩次MD5后的數據,暫稱之為密碼密鑰吧)作為密鑰來解密請求登陸回復包,在請求登陸回復包會包含一個會話密鑰,這個會話密鑰就是聊天數據包加密和解密的密鑰(有資料也提到一種例外,當好友離線的時,你發送信息給他,他下次上線的時候根本就不知道你當時發送信息的會話密鑰,這是他會用密碼密鑰來解密信息數據包)。
這里小總結一下幾種包所用到的密鑰:
登陸請求包: 隨機密鑰。
登陸請求回復包: 密碼密鑰。
信息發送包: 會話密鑰。
在線信息接收包: 會話密鑰。
離線信息接收包: 密碼密鑰。
2.2.數據包的加密和解密算法
QQ采用了最初的TEA算法做其核心的加密算法,TEA是Tiny Encrypt Arithmetic的縮寫。顧名思義就是一種比較簡單的小型加密算法,是在1994年由英國劍橋大學的David Wheeler和Roger Needham所發明的一種加密方法。它用一個16字節的密鑰去加密一個8字節的明文,得到一個8字節的密文,也可以反向從密文解密出明文。這種算法的可靠性是通過加密輪數而不是算法的復雜度來保證的。
QQ使用的TEA雖然是標準的TEA,但是QQ在使用這個算法的時候,由于需要加密不定長的數據,所以使用了一些常規的填充辦法和交織算法(也就是說,把前一組的加密結果和后一組未加密的結果進行運算,產生新的結果)。QQ消息被分為多個加密單元,每一個加密單元都是8字節,使用TEA進行加密,加密結果再作為下一個單元的密鑰。如果明文本身的長度不是8的倍數,那么還要進行填充,使其成為8的倍數。填充的時候會用一個32位隨機數存放于明文的開始位置,再在明文的最后用0填充為整個長度是8的倍數。由于會向后反饋,這樣即使對于相同的明文,因為使用了不同的隨機數,也會產生完全不同的密文。使用這種特殊的填充反饋算法所導致的結果就是,一段密文只能用加密它的密鑰進行解密,如果使用不正確的密鑰,就無法得到正確的填充結果。最常見的就是解密后得到的填充數值不是0,這樣就判斷解密失敗。
QQ消息的加密算法是一個16次的迭代過程,并且是反饋的,每一個加密單元是8字節,輸出也是8字節,密鑰是16字節
以prePlain表示前一個明文塊,plain表示當前明文塊,crypt表示當前明文塊加密得到的密文塊,preCrypt表示前一個密文塊
f表示加密算法, 那么從plain得到crypt的過程是: crypt = f(plain ˆ preCrypt ) &circ
d表示解密算法,從crypt得到plain的過程自然是 plain = d(crypt ˆ prePlain) ˆ
填充機制,其會在明文前和明文后分別填充一定的字節數,以保證明文長度是8字節的倍數填充的字節數與原始明文長度有關,填充的方法是:
------- 消息填充算法 -----------
a = (明文長度 + 10) mod 8 //計算填充長度
if(a 不等于 0) a = 8 - a;
b = 隨機數 & 0xF8 | a; //這個的作用是把a的值保存了下來
plain[0] = b; //然后把b做為明文的第0個字節,這樣第0個字節就保存了a的信息,這個信息在解密時就要用來找到真正明文的起始位置
plain[1 至 a+2] = 隨機數 & 0xFF; // 這里用隨機數填充明文的第1到第a+2個字節
plain[a+3 至 a+3+明文長度-1] = 明文; //從a+3字節開始才是真正的明文
plain[a+3+明文長度, 最后] = 0; //在最后,填充0,填充到總長度為8的整數為止。到此為止,結束了,這就是最后得到的要加密的明文內容
------- 消息填充算法 ------------
3.小結
3.1 小結一下
研究到現在為止,還沒有發現密碼密鑰(即密碼的兩次MD5的結果)在網絡上傳輸。但是,密碼密鑰是一個非常重要的密鑰,雖然用到這個密鑰并不比會話密鑰頻繁,但是要得到會話密鑰首先要取得密碼密鑰。幾個重要的密鑰使用流程是這樣的:

能正確解析各種包以及包的各部分和取得對應的加密解密密鑰就能進行正常的數據通訊。
3.2 留下的問題
密碼密鑰是否在網絡上傳送?獲取密碼密鑰是從本地獲取還是網絡上獲取?
posted on 2007-07-12 14:19
三告習習 閱讀(7205)
評論(8) 編輯 收藏 所屬分類:
LumaQQ