网上看到了discuz的Passport的加密算法。按这个贴子的说法,我理解的意思是生成随机数key做为密钥 然后再与明文txt做异或,生成密文。将密钥key做md5后放在密文前面。加密应该就是这个意思了吧,但是解密不太明白。现在已经有了密文,但是前面的密钥是md5过的呀,怎么解密?另外,代码最后一个函数,passport_encode是做什么用的?这应该是个对称算法吧。比如我想用到url的加解密。呵,比较笨,表笑话我噢,谢谢各位老师~~  另外,还有没有比较好的php对称和非对称加密算法,告诉我网址或名称吧,最好有详细说明,谢谢您哈~~下面贴出这个算法来:discuz通行证用对称密钥的加密,基于任何一数与结果异或必然得到另一个数,所以是一个可逆的算法,使用密钥的每位轮回加密数据的每位.
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);}

解决方案 »

  1.   

    这个地方MD5加密后 并不需要再解密 加密后的字符串只是作为中介的角色 核心在于异或算法 楼主可以调试下观察整个过程
    passport_encode 把传递过来的元素urlencode编码后 以&符拼接 楼主贴的这个算法里没有用到这个函数
      

  2.   

    注解太多, 反把我看晕了, discuz里有个可逆向加解密的函数叫authcode(), 不知你要来做什么用途?
      

  3.   

    楼上的大哥,比如我想传参用,写到url中,可以吗?这个函数好像要求明文和密钥都写进来才加密吧?discuz里用这个做什么呢?另外,您说的authcode()  有代码吗?怎么实现的加解密呢?
      

  4.   

    function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) { $ckey_length = 4;
    $key = md5($key ? $key : $GLOBALS['discuz_auth_key']);
    $keya = md5(substr($key, 0, 16));
    $keyb = md5(substr($key, 16, 16));
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : ''; $cryptkey = $keya.md5($keya.$keyc);
    $key_length = strlen($cryptkey); $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
    $string_length = strlen($string); $result = '';
    $box = range(0, 255); $rndkey = array();
    for($i = 0; $i <= 255; $i++) {
    $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    } for($j = $i = 0; $i < 256; $i++) {
    $j = ($j + $box[$i] + $rndkey[$i]) % 256;
    $tmp = $box[$i];
    $box[$i] = $box[$j];
    $box[$j] = $tmp;
    } for($a = $j = $i = 0; $i < $string_length; $i++) {
    $a = ($a + 1) % 256;
    $j = ($j + $box[$a]) % 256;
    $tmp = $box[$a];
    $box[$a] = $box[$j];
    $box[$j] = $tmp;
    $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    } if($operation == 'DECODE') {
    if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
    return substr($result, 26);
    } else {
    return '';
    }
    } else {
    return $keyc.str_replace('=', '', base64_encode($result));
    }}