关于DZ的Authcode函数转JS版的问题。
http://bbs.csdn.net/topics/390310377?page=1#post-393233055
我尝试把这个php版本的authcode写成了js版本的,但是结果相差太远。
PHP中对应JS的一些函数可以在这里找到:
chr: http://phpjs.org/functions/chr/
ord: http://phpjs.org/functions/ord/
Base64.encode,Base64.decode http://www.webtoolkit.info/javascript-base64.html
md5: http://phpjs.org/functions/md5/
其中Base64.encode和Base64.decode 测试结果与php的一样、。
那个帖子中, 版主说“由于涉及字符集问题(js 始终使用unicode),直译后与php不对等,没有大大意义”。
DZ的Authcode函数中用了RC4算法,
for($a = $j = $i = 0; $i
这部分如果写成JS版本,那么问题就和php版的不一样了。$string 在这段代码还没运行之前是一样的,但是运行过后就对不上了。
附代码: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;i0) && 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;}
php 版:// 参数解释 // $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 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;i0) && 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;}
这里基本上没采用替代版的CHR,ORD,等,都用的JS只带的。我的测试页面编码都是UTF-8编码。
这里的Base64.encode与php的base64_encode结果一样。
前文说的ord,chr 都有提供JS版本的。
chr:http://phpjs.org/functions/chr/
ord:http://phpjs.org/functions/ord/原本放在源码的加密解密数据,你现在用JS来实现,那么问一下,密匙你准备怎么处理?直接放在JS里么?
原本放在源码的加密解密数据,你现在用JS来实现,那么问一下,密匙你准备怎么处理?直接放在JS里么?
傻逼客户说明文传输。。。。二逼老板慌了。。。所以要求客户端加密。。。。
原本放在源码的加密解密数据,你现在用JS来实现,那么问一下,密匙你准备怎么处理?直接放在JS里么?
傻逼客户说明文传输。。。。二逼老板慌了。。。所以要求客户端加密。。。。
努力攻克难关,交货后让他们被黑掉吧
原本放在源码的加密解密数据,你现在用JS来实现,那么问一下,密匙你准备怎么处理?直接放在JS里么?
傻逼客户说明文传输。。。。二逼老板慌了。。。所以要求客户端加密。。。。
努力攻克难关,交货后让他们被黑掉吧
唉,想通了。这样做没意义。客户端的,都是可见的。
我参考了tx的登录加密的办法,放弃这个了。。
原本放在源码的加密解密数据,你现在用JS来实现,那么问一下,密匙你准备怎么处理?直接放在JS里么?
傻逼客户说明文传输。。。。二逼老板慌了。。。所以要求客户端加密。。。。
努力攻克难关,交货后让他们被黑掉吧
唉,想通了。这样做没意义。客户端的,都是可见的。
我参考了tx的登录加密的办法,放弃这个了。。