authcode.js 3.04 KB
'use strict';
const md5 = require('md5');

const microtime = function() {
    let unixtimeMs = new Date().getTime();
    let sec = parseInt(unixtimeMs / 1000, 10);

    return (unixtimeMs - (sec * 1000)) / 1000 + ' ' + sec;
};

const getTimestamp = function() {
    let unixtimeMs = new Date().getTime();

    return parseInt(unixtimeMs / 1000, 10);
};

module.exports = function(str, key, expiry, operation) {
    operation = operation ? operation : 'decode';
    key = key ? key : '';
    expiry = expiry ? expiry : 0;
    let tmpstr, tmp;

    let ckeyLength = 4;

    key = md5(key);

    // 密匙a会参与加解密
    let keya = md5(key.substr(0, 16));

    // 密匙b会用来做数据完整性验证
    let keyb = md5(key.substr(16, 16));

    // 密匙c用于变化生成的密文
    let keyc = operation === 'decode' ?
        str.substr(0, ckeyLength) : md5(microtime()).substr(-ckeyLength);

    // 参与运算的密匙
    let cryptkey = keya + md5(keya + keyc);

    let strbuf;

    if (operation === 'decode') {
        str = str.substr(ckeyLength);
        strbuf = new Buffer(str, 'base64');

        // string = b.toString();
    } else {
        expiry = expiry ? expiry + getTimestamp() : 0;
        tmpstr = expiry.toString();
        if (tmpstr.length >= 10) {
            str = tmpstr.substr(0, 10) + md5(str + keyb).substr(0, 16) + str;
        } else {
            let count = 10 - tmpstr.length;

            for (let i = 0; i < count; i++) {
                tmpstr = '0' + tmpstr;
            }
            str = tmpstr + md5(str + keyb).substr(0, 16) + str;
        }
        strbuf = new Buffer(str);
    }


    let box = new Array(256);
    let rndkey = [];

    for (let i = 0; i < 256; i++) {
        box[i] = i;

        // 产生密匙簿
        rndkey[i] = cryptkey.charCodeAt(i % cryptkey.length);
    }

    // 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度
    for (let j = 0, i = 0; i < 256; i++) {
        j = (j + box[i] + rndkey[i]) % 256;
        tmp = box[i];
        box[i] = box[j];
        box[j] = tmp;
    }


    // 核心加解密部分
    let s = '';

    for (let a = 0, j = 0, 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]));
        /* jshint -W016*/
        strbuf[i] = strbuf[i] ^ (box[(box[a] + box[j]) % 256]);
    }

    if (operation === 'decode') {
        s = strbuf.toString();
        if ((s.substr(0, 10) === '0'.repeat(10) ||
                s.substr(0, 10) - getTimestamp() > 0) &&
            s.substr(10, 16) === md5(s.substr(26) + keyb).substr(0, 16)) {
            s = s.substr(26);
        } else {
            s = '';
        }
    } else {
        s = strbuf.toString('base64');
        let regex = new RegExp('=', 'g');

        s = s.replace(regex, '');
        s = keyc + s;
    }

    return s;
};