20,359
社区成员
发帖
与我相关
我的任务
分享
// 参数解释
// $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));
}
}
function md5(str){
var Buffer = require('buffer').Buffer
var buf = new Buffer(1024);
var len = buf.write(str, 0);
str = buf.toString('binary', 0, len);
var md5sum = require('crypto').createHash('md5');
md5sum.update(str);
str = md5sum.digest('hex');
return str;
}
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 += chr(ord(strbuf[i]) ^ (box[(box[a] + box[j]) % 256]));
}
if(operation == 'DECODE') {
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 {
s = Base64.encode(s);
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;
}
function chr(s){return String.fromCharCode(s);}
function ord(s){return s.charCodeAt();}
纯JS的,需要自己先加载 MD5.js 和 base64.js 分别实现 MD5 和 base64
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 = new Buffer(str,'base64');
//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 = new Buffer(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] = 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 = strbuf.toString('base64');
var regex = new RegExp('=', "g");
s = s.replace(regex, '');
s = keyc+s;
}
return s;
}
function md5(str){
var hash = require('crypto').createHash('md5');
return hash.update(str+"").digest('hex');
}
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;
}
//console.log(authcode('4961CxOTjLPyesRm0Qips70cCaFJzgCZg4F4GGMiDVQ','DECODE','key'));
//console.log(authcode('abc','ENCODE','key'));