日期:2014-05-16  浏览次数:20448 次

一个类似 Base64 但真正实现了加密的 JS 文字加密算法
算法的基本原理和 Base64 类似。Base64 算法请参见维基百科 http://zh.wikipedia.org/zh-cn/Base64。

这里把 Base64 中使用的基本字符表进行了随机化——即用基本字符表排列的随机性作为密钥的变化性。同时,考虑编码方法的应用环境多为 Javascript,故将 Base64 规范字符表中的 “+/=” 改成了 “$_~”,便于网络传输和变量命名等。

对 “纯单字节” 字符串或 “纯双字节” 字符串,密文的长度增长 0.35 倍左右;在单/双字节混合的字符串中,因为需要在 “单/双字节序列” 间插入标识码(状态指示),故密文的长度会有所加长,但也不会增加太多。

该加密法的密文长度增加量略低于 “进制乱序法”,加密强度约为 296 位(64 的阶乘),算法中没有加入 “平移” 的二次操作,如果嫌加密强度不够,可以简单的对密文进行平移操作(详见 http://rubel.iteye.com/blog/891657)。

算法的编写参考了 《base64的js实现》,在此致谢!(注:该算法中未对编码串作 76 字符分段)

算法 4: Base64 变形加密法

(function() {
    //
    // 密文字符集(size:65)。
    // [0-9A-Za-z$_~]
    //
    var _hexCHS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$_~';

    //
    // Base64 变形加密法
    // 算法与 Base64 类似,即将 8 位字节用 6 位表示。
    // 规则:
    // 1. 码值 <= 0xff 的用 1 个字节表示;
    // 2. 码值 > 0xff 的用 2 字节表示;
    // 3. 单/双字节序列间用 0x1d 进行分隔;
    // 4. 首字为双字节时即前置 0x1d 分隔符。
    //
    // @param array key  - [0-63] 互斥值数组,length == 64
    // 
    Hex64 = function( key )
    {
        this._key = [], this._tbl = {};

        for (var _i=0; _i<64; ++_i) {
            this._key[_i] = _hexCHS.charAt(key[_i]);
            this._tbl[this._key[_i]] = _i;
        }

        this._pad = _hexCHS.charAt(64);
    };

    // 加密
    Hex64.prototype.enc = function( s )
    {
        var _rs = '';
        var _c1, _c2, _c3, _n1, _n2, _n3, _n4;
        var _i = 0;
        var _a = Hex64._2to1(s);
        var _en = _a.length % 3, _sz = _a.length - _en;
        while (_i < _sz) {
            _c1 = _a[_i++];
            _c2 = _a[_i++];
            _c3 = _a[_i++];
            _n1 = _c1 >> 2;
            _n2 = ((_c1 & 3) << 4) | (_c2 >> 4);
            _n3 = ((_c2 & 15) << 2) | (_c3 >> 6);
            _n4 = _c3 & 63;
            _rs += this._key[_n1]
                + this._key[_n2]
                + this._key[_n3]
                + this._key[_n4];
        }
        if (_en > 0) {
            _c1 = _a[_i++];
            _c2 = _en > 1 ? _a[_i] : 0;
            _n1 = _c1 >> 2;
            _n2 = ((_c1 & 3) << 4) | (_c2 >> 4);
            _n3 = (_c2 & 15) << 2;
            _rs += this._key[_n1] + this._key[_n2]
                + (_n3 ? this._key[_n3] : this._pad)
                + this._pad;
        }
        return  _rs.replace(/.{76}/g, function(s) {
            return  s + '\n';
        });
    };

    // 解密
    Hex64.prototype.dec = function( s )
    {
        var _sa = [],
            _n1, _n2, _n3, _n4,
            _i = 0, _c = 0;
        s = s.replace(/[^0-9A-Za-z$_~]/g, '');
        while (_i < s.length) {
            _n1 = this._tbl[s.charAt(_i++)];
            _n2 = this._tbl[s.charAt(_i++)];
            _n3 = this._tbl[s.charAt(_i++)];
            _n4 = this._tbl[s.charAt(_i++)];
            _sa[_c++] = (_n1 << 2) | (_n2 >> 4);
            _sa[_c++] = ((_n2 & 15) << 4) | (_n3 >> 2);
            _sa[_c++] = ((_n3 & 3) << 6) | _n4;
        }
        var _e2 = s.slice(-2);
        if (_e2.charAt(0) == this._pad) {
            _sa.length = _sa.length - 2;
        } else if (_e2.charAt(1) == this._pad) {
            _sa.length = _sa.length - 1;
        }
        return  Hex64._1to2(_sa);
    };

    //
    // 辅助:
    // Unicode 字符串 -> 单字节码值数组
    // 注意:
    // 原串中值为 0x1d 的字节(非字符)会被删除。
    //
    // @param string s  - 字符串(UCS-16)
    // @return array  - 单字节码值数组
    //
    Hex64._2to1 = function( s )
    {
        var _2b = false, _n = 0, _sa = [];

        if (s.charCodeAt(0) > 0xff) {
            _2b = true;
            _sa[_n++] = 0x1d;
        }
        for (var _i=0; _i<s.length; ++_i) {
            var _c = s.charCodeAt(_i);
            if (_c == 0x1d) continue;
            if (_c <= 0xff) {
                if (_2b) {