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

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

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

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