Maison > Article > développement back-end > 关于DZ的Authcode函数转JS版的问题。
之前论坛有人问起过这个问题,原文
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])); }
function authcode(str, operation, key, expiry) { var operation = operation ? operation : 'DECODE'; var key = key ? key : ''; var expiry = expiry ? expiry : 0; var ckey_length = 4; key = md5(key); // 密匙a会参与加解密 var keya = md5(key.substr(0, 16)); // 密匙b会用来做数据完整性验证 var keyb = md5(key.substr(16, 16)); // 密匙c用于变化生成的密文 var keyc = ckey_length ? (operation == 'DECODE' ? str.substr(0, ckey_length): md5(microtime()).substr(-ckey_length)) : ''; // 参与运算的密匙 var cryptkey = keya+md5(keya+keyc); var strbuf; if(operation == 'DECODE') { str = str.substr(ckey_length); strbuf = Base64.decode(str); //string = b.toString(); } else { expiry = expiry ? expiry + time() : 0; tmpstr = expiry.toString(); if(tmpstr.length>=10) str = tmpstr.substr(0,10)+md5(str+keyb).substr(0, 16)+str; else { var count = 10 - tmpstr.length; for(var i=0;i<count;i++) { tmpstr = '0'+tmpstr; } str = tmpstr+md5(str+keyb).substr(0, 16)+str; } strbuf = str; } var box = new Array(256); for(var i=0; i < 256; i++) { box[i] = i; } var rndkey = new Array(); // 产生密匙簿 for(var i=0; i < 256; i++) { rndkey[i] = cryptkey.charCodeAt(i % cryptkey.length); } // 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度 for(var j = i = 0; i < 256; i++) { j = (j + box[i] + rndkey[i]) % 256; tmp = box[i]; box[i] = box[j]; box[j] = tmp; } // 核心加解密部分 var s = ''; for(var a = j = i = 0; i < strbuf.length; i++) { a = (a + 1) % 256; j = (j + box[a]) % 256; tmp = box[a]; box[a] = box[j]; box[j] = tmp; // 从密匙簿得出密匙进行异或,再转成字符 //s += String.fromCharCode(string[i] ^ (box[(box[a] + box[j]) % 256])); strbuf[i] =chr(ord(strbuf[i]) ^ (box[(box[a] + box[j]) % 256])) } if(operation == 'DECODE') { var s = strbuf.toString(); if((s.substr(0, 10) == 0 || s.substr( 0, 10) - time() > 0) && s.substr(10, 16) == md5(s.substr(26)+keyb).substr(0, 16)) { s = s.substr(26); } else { s = ''; } } else { var s = Base64.encode(strbuf.toString()); var regex = new RegExp('=', "g"); s = s.replace(regex, ''); s = keyc+s; } return s;} function time() { var unixtime_ms = new Date().getTime(); return parseInt(unixtime_ms / 1000);}function microtime(get_as_float) { var unixtime_ms = new Date().getTime(); var sec = parseInt(unixtime_ms / 1000); return get_as_float ? (unixtime_ms/1000) : (unixtime_ms - (sec * 1000))/1000 + ' ' + sec;}
// 参数解释 // $string: 明文 或 密文 // $operation:DECODE表示解密,其它表示加密 // $key: 密匙 // $expiry:密文有效期 function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) { // 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙 $ckey_length = 4; // 密匙 $key = md5($key ? $key : $GLOBALS['discuz_auth_key']); // 密匙a会参与加解密 $keya = md5(substr($key, 0, 16)); // 密匙b会用来做数据完整性验证 $keyb = md5(substr($key, 16, 16)); // 密匙c用于变化生成的密文 $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : ''; // 参与运算的密匙 $cryptkey = $keya.md5($keya.$keyc); $key_length = strlen($cryptkey); // 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),解密时会通过这个密匙验证数据完整性 // 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确 $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') { // substr($result, 0, 10) == 0 验证数据有效性 // substr($result, 0, 10) - time() > 0 验证数据有效性 // substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性 // 验证数据有效性,请看未加密明文的格式 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 { // 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因 // 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码 return $keyc.str_replace('=', '', base64_encode($result)); } }
js 代码部分
68 strbuf[i] =chr(ord(strbuf[i]) ^ (box[(box[a] + box[j]) % 256]))
这个 strbuf 是数组吗?
无论从
21 strbuf = Base64.decode(str);
还是
36 strbuf = str;
上看,strbuf 都是字符串
那么 strbuf[i] = 'x' 这样写是无效的,虽然不报错
同样 ord(strbuf[i]) 也是不能返回正确值的
对应 ord(strbuf[i]) 的 js 是
strbuf.charCodeAt(i)
对应 chr(n) 的 js 是
String.fromCharCode(n)
没有认真去看你提供的php同名函数,但至少你的 js 取值、赋值部分已经就出问题了
另外:
DZ 的发行版是分 utf-8 和 gbk 的
由于字符内码的原因,utf-8 版中的 Authcode 编码结果是不能在 gbk 版中正确解码的(解出的还是utf-8的)
当然如果不含有中文是没有问题的,这一点你在测试的时候一定要注意
那个 Base64 类也是针对 utf-8 编码的。如果 php 端不是 utf-8 的,你也不能得到相同的结果
不好意思,疏忽了。发错了版本。
这段代码是我最后修正的结果:
function authcode(str, operation, key, expiry) { var operation = operation ? operation : 'DECODE'; var key = key ? key : ''; var expiry = expiry ? expiry : 0; var ckey_length = 4; key = md5(key); // 密匙a会参与加解密 var keya = md5(key.substr(0, 16)); // 密匙b会用来做数据完整性验证 var keyb = md5(key.substr(16, 16)); // 密匙c用于变化生成的密文 var keyc = ckey_length ? (operation == 'DECODE' ? str.substr(0, ckey_length): md5(microtime()).substr(-ckey_length)) : ''; // 参与运算的密匙 var cryptkey = keya+md5(keya+keyc); var string=""; if(operation == 'DECODE') { string =Base64.decode(str.substr(ckey_length)); } else { expiry = expiry ? expiry + time() : 0; tmpstr = expiry.toString(); if(tmpstr.length>=10) string = tmpstr.substr(0,10)+md5(str+keyb).substr(0, 16)+str; else { var count = 10 - tmpstr.length; for(var i=0;i<count;i++) { tmpstr = '0'+tmpstr; } string = tmpstr+md5(str+keyb).substr(0, 16)+str; } } var box = new Array(256); for(var i=0; i < 256; i++) { box[i] = i; } var rndkey = new Array(); // 产生密匙簿 for(var i=0; i < 256; i++) { rndkey[i] = cryptkey.charCodeAt(i % cryptkey.length); } // 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度 for(var j = i = 0; i < 256; i++) { j = (j + box[i] + rndkey[i]) % 256; tmp = box[i]; box[i] = box[j]; box[j] = tmp; } // 核心加解密部分 var result = ''; for(var 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+=String.fromCharCode(string.charCodeAt(i) ^ (box[(box[a] + box[j]) % 256])); } if(operation == 'DECODE') { var s=""; if((result.substr(0, 10) == 0 || result.substr( 0, 10) - time() > 0) && result.substr(10, 16) == md5(result.substr(26)+keyb).substr(0, 16)) { s = result.substr(26); } } else { var s = Base64.encode(result); var regex = new RegExp('=', "g"); s = s.replace(regex, ''); s = keyc+s; } return s;}
原本放在源码的加密解密数据,你现在用JS来实现,那么问一下,密匙你准备怎么处理?直接放在JS里么?
原本放在源码的加密解密数据,你现在用JS来实现,那么问一下,密匙你准备怎么处理?直接放在JS里么?
傻逼客户说明文传输。。。。二逼老板慌了。。。所以要求客户端加密。。。。
原本放在源码的加密解密数据,你现在用JS来实现,那么问一下,密匙你准备怎么处理?直接放在JS里么?
傻逼客户说明文传输。。。。二逼老板慌了。。。所以要求客户端加密。。。。
努力攻克难关,交货后让他们被黑掉吧
原本放在源码的加密解密数据,你现在用JS来实现,那么问一下,密匙你准备怎么处理?直接放在JS里么?
傻逼客户说明文传输。。。。二逼老板慌了。。。所以要求客户端加密。。。。
努力攻克难关,交货后让他们被黑掉吧
唉,想通了。这样做没意义。客户端的,都是可见的。
我参考了tx的登录加密的办法,放弃这个了。。
原本放在源码的加密解密数据,你现在用JS来实现,那么问一下,密匙你准备怎么处理?直接放在JS里么?
傻逼客户说明文传输。。。。二逼老板慌了。。。所以要求客户端加密。。。。
努力攻克难关,交货后让他们被黑掉吧
唉,想通了。这样做没意义。客户端的,都是可见的。
我参考了tx的登录加密的办法,放弃这个了。。