Discuz通行證的加密演算法

hzczichao發表於2010-07-01
discuz通行證用對稱金鑰的加密,基於任何一數與結果異或必然得到另一個數,所以是一個可逆的演算法,使用金鑰的每位輪迴加密資料的每位.[@more@]
passport_encrypt函式使用時隨機數來加密,然後把金鑰放在密文的前面,最後呼叫的passport_key才是真正的加密解密函式,那為什麼這樣做?金鑰和密文放在一起看起來沒用,我剛開始也這麼想,後來發現這恰恰是最重要的,因為是基於異或加密,也就是說,使用者知道任意兩個數就可以得到第三個數,當使用者輸一個明文進去,得到一個密文,再異或就能得到金鑰,這是不被允許,discuz是如何防止的?採用隨機數,然後MD5,接在與使用者輸入的前面,這樣使用者就不知道自己的輸入,當然他可以試,每一個數有三十六個可能,discuzMD5了一下金鑰,要試36的32的方,而且這樣也只是得到了一個MD5,邏輯上不大可能.
要做首頁和論壇的通行證了,所以分析一下這個,可能那邊要在jsp上面實現吧.哎
/**
* Passport 加密函式
*
* @param string 等待加密的原字串
* @param string 私有密匙(用於解密和加密)
*
* @return string 原字串經過私有密匙加密後的結果
*/
function passport_encrypt($txt, $key) {
//R 使用隨機數加密,金鑰放在字元前面
// 使用隨機數發生器產生 0~32000 的值並 MD5()
srand((double)microtime() * 1000000);
$encrypt_key = md5(rand(0, 32000));

// 變數初始化
$ctr = 0;
$tmp = '';

// for 迴圈,$i 為從 0 開始,到小於 $txt 字串長度的整數
for($i = 0; $i < strlen($txt); $i++) {
// 如果 $ctr = $encrypt_key 的長度,則 $ctr 清零
$ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;
// $tmp 字串在末尾增加兩位,其第一位內容為 $encrypt_key 的第 $ctr 位,
// 第二位內容為 $txt 的第 $i 位與 $encrypt_key 的 $ctr 位取異或。然後 $ctr = $ctr + 1
$tmp .= $encrypt_key[$ctr].($txt[$i] ^ $encrypt_key[$ctr++]);
}

// 返回結果,結果為 passport_key() 函式返回值的 base65 編碼結果
return base64_encode(passport_key($tmp, $key)); //R 真正使用密碼加密

}

/**
* Passport 解密函式
*
* @param string 加密後的字串
* @param string 私有密匙(用於解密和加密)
*
* @return string 字串經過私有密匙解密後的結果
*/
function passport_decrypt($txt, $key) {

// $txt 的結果為加密後的字串經過 base64 解碼,然後與私有密匙一起,
// 經過 passport_key() 函式處理後的返回值
$txt = passport_key(base64_decode($txt), $key); //R 二次加密就是解密

// 變數初始化
$tmp = '';

// for 迴圈,$i 為從 0 開始,到小於 $txt 字串長度的整數
for ($i = 0; $i < strlen($txt); $i++) {
// $tmp 字串在末尾增加一位,其內容為 $txt 的第 $i 位,
// 與 $txt 的第 $i + 1 位取異或。然後 $i = $i + 1
$tmp .= $txt[$i] ^ $txt[++$i]; R //解密隨機加密;
}

// 返回 $tmp 的值作為結果
return $tmp;

}

/**
* Passport 密匙處理函式
*
* @param string 待加密或待解密的字串
* @param string 私有密匙(用於解密和加密)
*
* @return string 處理後的密匙
*/
function passport_key($txt, $encrypt_key) {

// 將 $encrypt_key 賦為 $encrypt_key 經 md5() 後的值
$encrypt_key = md5($encrypt_key);

// 變數初始化
$ctr = 0;
$tmp = '';

// for 迴圈,$i 為從 0 開始,到小於 $txt 字串長度的整數
for($i = 0; $i < strlen($txt); $i++) {
// 如果 $ctr = $encrypt_key 的長度,則 $ctr 清零
$ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr; //R 輪
// $tmp 字串在末尾增加一位,其內容為 $txt 的第 $i 位,
// 與 $encrypt_key 的第 $ctr + 1 位取異或。然後 $ctr = $ctr + 1
$tmp .= $txt[$i] ^ $encrypt_key[$ctr++]; //R 輪翻異或加密;
}

// 返回 $tmp 的值作為結果
return $tmp;

}

/**
* Passport 資訊(陣列)編碼函式
*
* @param array 待編碼的陣列
*
* @return string 陣列經編碼後的字串
*/
function passport_encode($array) {

// 陣列變數初始化
$arrayenc = array();

// 遍歷陣列 $array,其中 $key 為當前元素的下標,$val 為其對應的值
foreach($array as $key => $val) {
// $arrayenc 陣列增加一個元素,其內容為 "$key=經過 urlencode() 後的 $val 值"
$arrayenc[] = $key.'='.urlencode($val);
}

// 返回以 "&" 連線的 $arrayenc 的值(implode),例如 $arrayenc = array('aa', 'bb', 'cc', 'dd'),
// 則 implode('&', $arrayenc) 後的結果為 ”aa&bb&cc&dd"
return implode('&', $arrayenc);

}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23595918/viewspace-1034814/,如需轉載,請註明出處,否則將追究法律責任。

相關文章