Discuz(php)的加密算法


Posted on November 26, 2008


私有密匙(passport_key)

由于一些关键参数采用了 GET 方式进行传递,即便两次 header 跳转并不会直接将链接显示在外面,但我们仍然对关键的参数进行了加密,私有 密匙共有两个作用:其一是供下面提到的可逆加密算法(AzDGCrypt)进行数据的加解密。其二是生成不可逆验证字串(verify),以防止关键信息被 伪造。

在启用 Discuz! Passort 后,您需要在应用程序和 Discuz! 后台配置两处私有密匙,这两处的内容必须完全相同,这样应用程序和论坛之间才能 正常通信。私有密匙决定了加密算法的强度,因此密匙长度请不要小于 10 个字节,并包含字母、数字和符号,以保证系统的安全。

加密算法

Discuz! Passport 采用 Azerbaijan Development Group(AzDG)开发的可逆加密算法 AzDGCrypt 对用户资料进行加密。如提供正确的私有密匙, 可通过本加密算法对数据进行加密及解密,因此只要保证私有密匙的保密性,即可确保数据传递过程中的安全。以下为 Discuz! Passport 中应用到 的可逆加密算法,为了生成可以被 Discuz! Passport 正确解密的 auth 字串,需要将如下函数放置于应用程序中,并可在登录及注册时调用。

passport_encrypt()是加密函数,用法为 passport_encrypt($txt, $key),其中 $txt 是待加密的字串,$key 是私有密匙。
passport_decrypt()是解密函数,用法为 passport_decrypt($txt, $key),其中 $txt 是加密后的字串,$key 是私有密匙。  

/**
* Passport 加密函数
*
* @param  string  等待加密的原字串
* @param  string  私有密匙(用于解密和加密)
*
* @return string  原字串经过私有密匙加密后的结果
*/
function passport_encrypt($txt, $key) {
 // 使用随机数发生器产生 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() 函数返回值的 base64 编码结果
 return base64_encode(passport_key($tmp, $key));
}
/**
* Passport 解密函数
*
* @param  string  加密后的字串
* @param  string  私有密匙(用于解密和加密)
*
* @return string  字串经过私有密匙解密后的结果
*/
function passport_decrypt($txt, $key) {
 // $txt 的结果为加密后的字串经过 base64 解码,然后与私有密匙一起,
 // 经过 passport_key() 函数处理后的返回值
 $txt = passport_key(base64_decode($txt), $key);
 // 变量初始化
 $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];
 }
 // 返回 $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;
  // $tmp 字串在末尾增加一位,其内容为 $txt 的第 $i 位,
  // 与 $encrypt_key 的第 $ctr + 1 位取异或。然后 $ctr = $ctr + 1
  $tmp .= $txt[$i] ^ $encrypt_key[$ctr++];
 }
 // 返回 $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);

passport_encode()是将数组转换合成为字串形式存储的函数:变量名和数值之间用等号连接,如果数值包含特殊字符,使用 urlencode() 将其转码。 多个变量间使用 & 分割。例如原始数组内容为 array(''username'' => ''abc'', ''email'' => ''my+discuz@gmail.com''),经过passport_encode() 编码后 结果为 username=abc&email=my%2Bdiscuz%40gmail.com。
 


标签:N/A

 

在线学习答案查询入口
微信扫一扫
微信扫码联系