xxtea 算法的 js 加密处理类,包含 UtfParser 和 Base64 类 ?

JavaScript 实现


新建 xxtea.js 文件

ES5 写法:

/*
* xxtea算法的js加密处理类,还包含了UtfParser类,还包含了Base64类
*/

//Class:Xxtea
export function Xxtea(privateKey) {
    this._keyString = privateKey;
}

//将长整形转换为string,private
Xxtea.prototype._long2str = function (v, w) {
    var vl = v.length;
    var n = (vl - 1) << 2;
    if (w) {
        var m = v[vl - 1];
        if ((m < n - 3) || (m > n)) return null;
        n = m;
    }
    for (var i = 0; i < vl; i++) {
        v[i] = String.fromCharCode(v[i] & 0xff,
                                   v[i] >>> 8 & 0xff,
                                   v[i] >>> 16 & 0xff,
                                   v[i] >>> 24 & 0xff);
    }
    if (w) {
        return v.join('').substring(0, n);
    }
    else {
        return v.join('');
    }
}

//将string转换为long,private
Xxtea.prototype._str2long = function (s, w) {
    var len = s.length;
    var v = [];
    for (var i = 0; i < len; i += 4) {
        v[i >> 2] = s.charCodeAt(i)
                  | s.charCodeAt(i + 1) << 8
                  | s.charCodeAt(i + 2) << 16
                  | s.charCodeAt(i + 3) << 24;
    }
    if (w) {
        v[v.length] = len;
    }
    return v;
}

//function: encrypt str with private key by xxtea
Xxtea.prototype.xxtea_encrypt = function (str) {
    if (str == "") {
        return "";
    }
    str = Base64.encode64(UtfParser.utf16to8(str));
    var v = this._str2long(str, true);
    var k = this._str2long(this._keyString, false);
    if (k.length < 4) {
        k.length = 4;
    }
    var n = v.length - 1;

    var z = v[n], y = v[0], delta = 0x9E3779B9;
    var mx, e, p, q = Math.floor(6 + 52 / (n + 1)), sum = 0;
    while (0 < q--) {
        sum = sum + delta & 0xffffffff;
        e = sum >>> 2 & 3;
        for (p = 0; p < n; p++) {
            y = v[p + 1];
            mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
            z = v[p] = v[p] + mx & 0xffffffff;
        }
        y = v[0];
        mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        z = v[n] = v[n] + mx & 0xffffffff;
    }

    return Base64.encode64(this._long2str(v, false));
}

//function: decrypt str with private key by xxtea
Xxtea.prototype.xxtea_decrypt = function (str) {
    if (str == "") {
        return "";
    }
    str = Base64.decode64(str);
    var v = this._str2long(str, false);
    var k = this._str2long(this._keyString, false);
    if (k.length < 4) {
        k.length = 4;
    }
    var n = v.length - 1;

    var z = v[n - 1], y = v[0], delta = 0x9E3779B9;
    var mx, e, p, q = Math.floor(6 + 52 / (n + 1)), sum = q * delta & 0xffffffff;
    while (sum != 0) {
        e = sum >>> 2 & 3;
        for (p = n; p > 0; p--) {
            z = v[p - 1];
            mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
            y = v[p] = v[p] - mx & 0xffffffff;
        }
        z = v[n];
        mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        y = v[0] = v[0] - mx & 0xffffffff;
        sum = sum - delta & 0xffffffff;
    }

    return UtfParser.utf8to16(Base64.decode64(this._long2str(v, true)));
}

//Class:utf16 to utf8, utf8 ot utf16
function UtfParser() {
    //all method is static
}

//function:change utf16 to utf8
//parms(str):string that you want to change
UtfParser.utf16to8 = function (str) {
    var out, i, len, c;

    out = "";
    len = str.length;
    for (i = 0; i < len; i++) {
        c = str.charCodeAt(i);
        if ((c >= 0x0001) && (c <= 0x007F)) {
            out += str.charAt(i);
        }
        else if (c > 0x07FF) {
            out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
            out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
            out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
        }
        else {
            out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
            out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
        }
    }
    return out;
}

//function:change utf8 to utf16
//parms(str):string that you want to change
UtfParser.utf8to16 = function (str) {
    str = str.toString();

    var out, i, len, c;
    var char2, char3;

    out = "";
    len = str.length;
    i = 0;
    while (i < len) {
        c = str.charCodeAt(i++);
        switch (c >> 4) {
            case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
                // 0xxxxxxx
                out += str.charAt(i - 1);
                break;
            case 12: case 13:
                // 110x xxxx   10xx xxxx
                char2 = str.charCodeAt(i++);
                out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
                break;
            case 14:
                // 1110 xxxx  10xx xxxx  10xx xxxx
                char2 = str.charCodeAt(i++);
                char3 = str.charCodeAt(i++);
                out += String.fromCharCode(((c & 0x0F) << 12) |
					       ((char2 & 0x3F) << 6) |
					       ((char3 & 0x3F) << 0));
                break;
        }
    }

    return out;
}


// Class:base64 encode & decode
function Base64() {
    //all method is static
}

//static
Base64._keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
Base64.encode64 = function (input) {
    var output = "";
    var chr1, chr2, chr3 = "";
    var enc1, enc2, enc3, enc4 = "";
    var i = 0;

    do {
        chr1 = input.charCodeAt(i++);
        chr2 = input.charCodeAt(i++);
        chr3 = input.charCodeAt(i++);

        enc1 = chr1 >> 2;
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
        enc4 = chr3 & 63;

        if (isNaN(chr2)) {
            enc3 = enc4 = 64;
        } else if (isNaN(chr3)) {
            enc4 = 64;
        }

        output = output +
           Base64._keyStr.charAt(enc1) +
           Base64._keyStr.charAt(enc2) +
           Base64._keyStr.charAt(enc3) +
           Base64._keyStr.charAt(enc4);
        chr1 = chr2 = chr3 = "";
        enc1 = enc2 = enc3 = enc4 = "";
    } while (i < input.length);

    return output;
}

Base64.decode64 = function (input) {
    var output = "";
    var chr1, chr2, chr3 = "";
    var enc1, enc2, enc3, enc4 = "";
    var i = 0;

    // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
    var base64test = /[^A-Za-z0-9\+\/\=\n]/g;
    if (base64test.exec(input)) {
        alert("There were invalid base64 characters in the input text.\n" +
              "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
              "Expect errors in decoding.");
    }
    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

    do {
        enc1 = Base64._keyStr.indexOf(input.charAt(i++));
        enc2 = Base64._keyStr.indexOf(input.charAt(i++));
        enc3 = Base64._keyStr.indexOf(input.charAt(i++));
        enc4 = Base64._keyStr.indexOf(input.charAt(i++));

        chr1 = (enc1 << 2) | (enc2 >> 4);
        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
        chr3 = ((enc3 & 3) << 6) | enc4;

        output = output + String.fromCharCode(chr1);

        if (enc3 != 64) {
            output = output + String.fromCharCode(chr2);
        }
        if (enc4 != 64) {
            output = output + String.fromCharCode(chr3);
        }

        chr1 = chr2 = chr3 = "";
        enc1 = enc2 = enc3 = enc4 = "";

    } while (i < input.length);

    return output;
}

ES6 写法:

'use strict';

const _keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const { error: _error } = console;
/**
 * @class Base64Class 帮助基类
 */
class Base64Class {
    // #region  基础属性设置 --------------------------------------------------------------------------------------------------------
    // constructor() {
    //     // private property
    //     // this._keyStr = _keyStr;
    // };
    // #endregion  基础属性设置--------------------------------------------------------------------------------------------------------
    // #region 静态方法 --------------------------------------------------------------------------------------------------------- */
    static init() {
        return new Base64Class();
    }
    // #endregion 静态方法--------------------------------------------------------------------------------------------------------- */

    // public method for encoding
    static encode(input) {
        let output = '';
        let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        let i = 0;

        input = Base64Class._utf8_encode(input);

        while (i < input.length) {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output += _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
        }

        return output;
    };

    // public method for decoding
    static decode(input) {
        let output = '';
        let chr1, chr2, chr3;
        let enc1, enc2, enc3, enc4;
        let i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');

        while (i < input.length) {
            enc1 = _keyStr.indexOf(input.charAt(i++));
            enc2 = _keyStr.indexOf(input.charAt(i++));
            enc3 = _keyStr.indexOf(input.charAt(i++));
            enc4 = _keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 !== 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 !== 64) {
                output = output + String.fromCharCode(chr3);
            }
        }

        output = this._utf8_decode(output);

        return output;
    };
    static encode64(input) {
        let output = '';
        let chr1; let chr2; let chr3 = '';
        let enc1; let enc2; let enc3; let enc4 = '';
        let i = 0;

        do {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output +
            _keyStr.charAt(enc1) +
            _keyStr.charAt(enc2) +
            _keyStr.charAt(enc3) +
            _keyStr.charAt(enc4);
            chr1 = chr2 = chr3 = '';
            enc1 = enc2 = enc3 = enc4 = '';
        } while (i < input.length);

        return output;
    }
    static decode64(input) {
        let output = '';
        let chr1; let chr2; let chr3 = '';
        let enc1; let enc2; let enc3; let enc4 = '';
        let i = 0;

        // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
        const base64test = /[^A-Za-z0-9\+\/\=\n]/g;
        if (base64test.exec(input)) {
            _error('There were invalid base64 characters in the input text.\n' +
                  "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
                  'Expect errors in decoding.');
        }
        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');

        do {
            enc1 = _keyStr.indexOf(input.charAt(i++));
            enc2 = _keyStr.indexOf(input.charAt(i++));
            enc3 = _keyStr.indexOf(input.charAt(i++));
            enc4 = _keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 !== 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 !== 64) {
                output = output + String.fromCharCode(chr3);
            }

            chr1 = chr2 = chr3 = '';
            enc1 = enc2 = enc3 = enc4 = '';
        } while (i < input.length);

        return output;
    }
    // private method for UTF-8 encoding
    static _utf8_encode(string) {
        string = string.replace(/\r\n/g, '\n');
        let utftext = '';

        for (let n = 0; n < string.length; n++) {
            const c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            } else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            } else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }

        return utftext;
    };

    // private method for UTF-8 decoding
    static _utf8_decode(utftext) {
        let string = '';
        let i = 0;
        let c = 0;
        // let c1 = 0;
        let c2 = 0;
        let c3 = 0;

        while (i < utftext.length) {
            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            } else if ((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i + 1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            } else {
                c2 = utftext.charCodeAt(i + 1);
                c3 = utftext.charCodeAt(i + 2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }
        }

        return string;
    };

    // #endregion 静态方法 --------------------------------------------------------------------------------------------------------
}

/**
 * @class UtfParserClass类
 */
class UtfParserClass {
    // #region  基础属性设置 --------------------------------------------------------------------------------------------------------
    // #endregion  基础属性设置--------------------------------------------------------------------------------------------------------

    // #region  静态方法 --------------------------------------------------------------------------------------------------------

    // #region 对象内部使用 --------------------------------------------------------------------------------------------------------

    // #region 对象内部使用 --- 基础实例化相关方法---------------------------------------------------------------
    /**
    * 用于对象实例化
    * @param {String} privateKey 用于加密的私钥
    * @returns {Object} 返回已经实例化完成的对象
    */
    static init() {
        const res = new UtfParserClass();
        return res;
    }
    // #endregion 对象内部使用 --- 基础实例化相关方法---------------------------------------------------------------

    // #endregion 对象内部使用--------------------------------------------------------------------------------------------------------

    // #region 对象外部使用 --------------------------------------------------------------------------------------------------------

    // function:change utf16 to utf8
    // parms(str):string that you want to change
    static utf16to8(str) {
        let out, i, c;
        const len = str.length;

        out = '';
        for (i = 0; i < len; i++) {
            c = str.charCodeAt(i);
            if ((c >= 0x0001) && (c <= 0x007F)) {
                out += str.charAt(i);
            } else if (c > 0x07FF) {
                out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
                out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
                out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
            } else {
                out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
                out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
            }
        }
        return out;
    }

    // function:change utf8 to utf16
    // parms(str):string that you want to change
    static utf8to16(str) {
        str = str.toString();

        const len = str.length;
        let out, i, c;
        let char2, char3;

        out = '';
        i = 0;
        while (i < len) {
            c = str.charCodeAt(i++);
            switch (c >> 4) {
                case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
                    // 0xxxxxxx
                    out += str.charAt(i - 1);
                    break;
                case 12: case 13:
                    // 110x xxxx  10xx xxxx
                    char2 = str.charCodeAt(i++);
                    out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
                    break;
                case 14:
                    // 1110 xxxx  10xx xxxx  10xx xxxx
                    char2 = str.charCodeAt(i++);
                    char3 = str.charCodeAt(i++);
                    out += String.fromCharCode(((c & 0x0F) << 12) |
               ((char2 & 0x3F) << 6) |
               ((char3 & 0x3F) << 0));
                    break;
            }
        }

        return out;
    }

    
    static utf8Encode(str) {
        // eslint-disable-next-line no-control-regex
        if (/^[\x00-\x7f]*$/.test(str)) {
            return str;
        }
        var buf = [];
        var n = str.length;
        for (var i = 0, j = 0; i < n; ++i, ++j) {
            var codeUnit = str.charCodeAt(i);
            if (codeUnit < 0x80) {
                buf[j] = str.charAt(i);
            } else if (codeUnit < 0x800) {
                buf[j] = String.fromCharCode(0xC0 | (codeUnit >> 6),
                    0x80 | (codeUnit & 0x3F));
            } else if (codeUnit < 0xD800 || codeUnit > 0xDFFF) {
                buf[j] = String.fromCharCode(0xE0 | (codeUnit >> 12),
                    0x80 | ((codeUnit >> 6) & 0x3F),
                    0x80 | (codeUnit & 0x3F));
            } else {
                if (i + 1 < n) {
                    var nextCodeUnit = str.charCodeAt(i + 1);
                    if (codeUnit < 0xDC00 && nextCodeUnit >= 0xDC00 && nextCodeUnit <= 0xDFFF) {
                        var rune = (((codeUnit & 0x03FF) << 10) | (nextCodeUnit & 0x03FF)) + 0x010000;
                        buf[j] = String.fromCharCode(0xF0 | ((rune >> 18) & 0x3F),
                            0x80 | ((rune >> 12) & 0x3F),
                            0x80 | ((rune >> 6) & 0x3F),
                            0x80 | (rune & 0x3F));
                        ++i;
                        continue;
                    }
                }
                throw new Error('Malformed string');
            }
        }
        return buf.join('');
    }

    static utf8DecodeShortString(bs, n) {
        var charCodes = new Array(n);
        var i = 0; var off = 0;
        for (var len = bs.length; i < n && off < len; i++) {
            var unit = bs.charCodeAt(off++);
            switch (unit >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    charCodes[i] = unit;
                    break;
                case 12:
                case 13:
                    if (off < len) {
                        charCodes[i] = ((unit & 0x1F) << 6) |
                            (bs.charCodeAt(off++) & 0x3F);
                    } else {
                        throw new Error('Unfinished UTF-8 octet sequence');
                    }
                    break;
                case 14:
                    if (off + 1 < len) {
                        charCodes[i] = ((unit & 0x0F) << 12) |
                            ((bs.charCodeAt(off++) & 0x3F) << 6) |
                            (bs.charCodeAt(off++) & 0x3F);
                    } else {
                        throw new Error('Unfinished UTF-8 octet sequence');
                    }
                    break;
                case 15:
                    if (off + 2 < len) {
                        var rune = (((unit & 0x07) << 18) |
                            ((bs.charCodeAt(off++) & 0x3F) << 12) |
                            ((bs.charCodeAt(off++) & 0x3F) << 6) |
                            (bs.charCodeAt(off++) & 0x3F)) - 0x10000;
                        if (rune >= 0 && rune <= 0xFFFFF) {
                            charCodes[i++] = (((rune >> 10) & 0x03FF) | 0xD800);
                            charCodes[i] = ((rune & 0x03FF) | 0xDC00);
                        } else {
                            throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16));
                        }
                    } else {
                        throw new Error('Unfinished UTF-8 octet sequence');
                    }
                    break;
                default:
                    throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16));
            }
        }
        if (i < n) {
            charCodes.length = i;
        }
        return String.fromCharCode.apply(String, charCodes);
    }

    static utf8DecodeLongString(bs, n) {
        var buf = [];
        var charCodes = new Array(0x8000);
        var i = 0; var off = 0;
        for (var len = bs.length; i < n && off < len; i++) {
            var unit = bs.charCodeAt(off++);
            switch (unit >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    charCodes[i] = unit;
                    break;
                case 12:
                case 13:
                    if (off < len) {
                        charCodes[i] = ((unit & 0x1F) << 6) |
                            (bs.charCodeAt(off++) & 0x3F);
                    } else {
                        throw new Error('Unfinished UTF-8 octet sequence');
                    }
                    break;
                case 14:
                    if (off + 1 < len) {
                        charCodes[i] = ((unit & 0x0F) << 12) |
                            ((bs.charCodeAt(off++) & 0x3F) << 6) |
                            (bs.charCodeAt(off++) & 0x3F);
                    } else {
                        throw new Error('Unfinished UTF-8 octet sequence');
                    }
                    break;
                case 15:
                    if (off + 2 < len) {
                        var rune = (((unit & 0x07) << 18) |
                            ((bs.charCodeAt(off++) & 0x3F) << 12) |
                            ((bs.charCodeAt(off++) & 0x3F) << 6) |
                            (bs.charCodeAt(off++) & 0x3F)) - 0x10000;
                        if (rune >= 0 && rune <= 0xFFFFF) {
                            charCodes[i++] = (((rune >> 10) & 0x03FF) | 0xD800);
                            charCodes[i] = ((rune & 0x03FF) | 0xDC00);
                        } else {
                            throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16));
                        }
                    } else {
                        throw new Error('Unfinished UTF-8 octet sequence');
                    }
                    break;
                default:
                    throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16));
            }
            if (i >= 0x7FFF - 1) {
                var size = i + 1;
                charCodes.length = size;
                buf[buf.length] = String.fromCharCode.apply(String, charCodes);
                n -= size;
                i = -1;
            }
        }
        if (i > 0) {
            charCodes.length = i;
            buf[buf.length] = String.fromCharCode.apply(String, charCodes);
        }
        return buf.join('');
    }

    // n is UTF16 length
    static utf8Decode(bs, n) {
        if (n === undefined || n === null || (n < 0)) n = bs.length;
        if (n === 0) return '';
        // eslint-disable-next-line no-control-regex
        if (/^[\x00-\x7f]*$/.test(bs) || !(/^[\x00-\xff]*$/.test(bs))) {
            if (n === bs.length) return bs;
            return bs.substr(0, n);
        }
        return ((n < 0x7FFF)
            ? UtfParserClass.utf8DecodeShortString(bs, n)
            : UtfParserClass.utf8DecodeLongString(bs, n));
    }

    // #endregion 对象外部使用--------------------------------------------------------------------------------------------------------
}

/**
 * @class XxteaClass类
 */
class XxteaClass {
    // #region  基础属性设置 --------------------------------------------------------------------------------------------------------
    constructor(privateKey) {
        this._keyString = privateKey;
    };
    // #endregion  基础属性设置--------------------------------------------------------------------------------------------------------

    // #region  静态方法 --------------------------------------------------------------------------------------------------------

    // #region 对象内部使用 --------------------------------------------------------------------------------------------------------

    // #region 对象内部使用 --- 基础实例化相关方法---------------------------------------------------------------
    /**
    * 用于对象实例化
    * @param {String} privateKey 用于加密的私钥
    * @returns {Object} 返回已经实例化完成的对象
    */
    static init(privateKey) {
        const res = new XxteaClass(privateKey);
        return res;
    }
    // #endregion 对象内部使用 --- 基础实例化相关方法---------------------------------------------------------------

    // #endregion 对象内部使用--------------------------------------------------------------------------------------------------------

    // #region 对象外部使用 --------------------------------------------------------------------------------------------------------
    // 将长整形转换为string,private
    _long2str(v, w) {
        const vl = v.length;
        let n = (vl - 1) << 2;
        if (w) {
            const m = v[vl - 1];
            if ((m < n - 3) || (m > n)) return null;
            n = m;
        }
        for (let i = 0; i < vl; i++) {
            v[i] = String.fromCharCode(v[i] & 0xff,
                v[i] >>> 8 & 0xff,
                v[i] >>> 16 & 0xff,
                v[i] >>> 24 & 0xff);
        }
        if (w) {
            return v.join('').substring(0, n);
        } else {
            return v.join('');
        }
    }

    // 将string转换为long,private
    _str2long(s, w) {
        const len = s.length;
        const v = [];
        for (let i = 0; i < len; i += 4) {
            v[i >> 2] = s.charCodeAt(i) |
              s.charCodeAt(i + 1) << 8 |
              s.charCodeAt(i + 2) << 16 |
              s.charCodeAt(i + 3) << 24;
        }
        if (w) {
            v[v.length] = len;
        }
        return v;
    }

    // function: encrypt str with private key by xxtea
    xxtea_encrypt(str) {
        if (!str) {
            return '';
        }
        // str = Base64Class.encode64(UtfParserClass.utf16to8(str));
        str = Base64Class.encode64(UtfParserClass.utf8Encode(str));
        const v = this._str2long(str, true);
        const k = this._str2long(this._keyString, false);
        if (k.length < 4) {
            k.length = 4;
        }
        const n = v.length - 1;

        let z = v[n]; let y = v[0]; const delta = 0x9E3779B9;
        let mx; let e; let p; let q = Math.floor(6 + 52 / (n + 1)); let sum = 0;
        while (q-- > 0) {
            sum = sum + delta & 0xffffffff;
            e = sum >>> 2 & 3;
            for (p = 0; p < n; p++) {
                y = v[p + 1];
                mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
                z = v[p] = v[p] + mx & 0xffffffff;
            }
            y = v[0];
            mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
            z = v[n] = v[n] + mx & 0xffffffff;
        }

        return Base64Class.encode64(this._long2str(v, false));
    }

    // function: decrypt str with private key by xxtea
    xxtea_decrypt(str) {
        if (!str) {
            return '';
        }
        str = Base64Class.decode64(str);
        const v = this._str2long(str, false);
        const k = this._str2long(this._keyString, false);
        if (k.length < 4) {
            k.length = 4;
        }
        const n = v.length - 1;

        let z = v[n - 1]; let y = v[0]; const delta = 0x9E3779B9;
        let mx; let e; let p; const q = Math.floor(6 + 52 / (n + 1)); let sum = q * delta & 0xffffffff;
        while (sum !== 0) {
            e = sum >>> 2 & 3;
            for (p = n; p > 0; p--) {
                z = v[p - 1];
                mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
                y = v[p] = v[p] - mx & 0xffffffff;
            }
            z = v[n];
            mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
            y = v[0] = v[0] - mx & 0xffffffff;
            sum = sum - delta & 0xffffffff;
        }

        // return UtfParserClass.utf8to16(Base64Class.decode64(this._long2str(v, true)));
        return UtfParserClass.utf8Decode(Base64Class.decode64(this._long2str(v, true)));
    }
    // #endregion 对象外部使用--------------------------------------------------------------------------------------------------------
}
export default {
  Xxtea: XxteaClass,
  Base64: Base64Class,
};

使用案例

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>xxtea加解密</title>
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <div>
        <h3>xxtea 加解密</h3>
        <input type="text" placeholder="请输入内容..." value="" id="content" />
        <button id="JiaMi">加密</button>
        <p><span>加密输出:</span></p>
        <textarea rows="3" cols="30"></textarea>
        <button id="JieMi">解密</button>
        <p><span>解密输出:</span></p>
        <textarea rows="3" cols="30"></textarea>
    </div>

    <script src="./xxtea.js"></script>
    <script src="./index.js"></script>
</body>
</html>

CSS:

*{
    margin:0;
    padding:0;
}
html,body{
    width:100%;
    height:100%;
    font-size:18px;
    font-family:'楷体';
}
div{
    width:300px;
    height:400px;
    border:1px solid rgba(0,0,0, .5);
    position:fixed;
    top:50%;
    left:50%;
    transform: translate(-50%,-50%);
}
div>input{
    width:80%;
    height:25px;
    margin:10px 10%;
    padding-left:10px;
}
div button{
    width:60px;
    height:25px;
    text-align:center;
    line-height:25px;
    border:none;
    background-color: deepskyblue;
    color:white;
    margin:10px 10%;
    cursor:pointer;
}
button:hover{
    background-color: dodgerblue;
    transition: all 1s;
}
p{
    margin:10px 10%;
    border-bottom:1px solid lightblue;
}
textarea{
      margin:0px 10%;
}
h3{
    width:100%;
    height:40px;
    background-color: rgba(0,0,0,.8);
    color:white;
    display:flex;
    justify-content: center;
    align-items: center;
}

JS:

 let valArr = document.querySelectorAll('textarea')
 let t = new Date().getTime()
 let xxtea = new XxteaClass("n+" + t)
 document.getElementById('JiaMi').onclick = () => {  
      let val = document.getElementById('content').value
      valArr[0].value = xxtea.xxtea_encrypt(val)
 }
 document.getElementById('JieMi').onclick = () => {
      valArr[1].value = xxtea.xxtea_decrypt(valArr[0].value)
 }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值