几个文字加密的 JS 简洁算法(续2)--进制乱序法

介绍一种新颖的文字加密方法——进制乱序法,通过对字符Unicode值进行基于随机排列进制表的转换,结合平移加密,实现高强度加密效果。适用于各种字符集,加密后的密文为纯英文大小写字母。
[size=medium]续前一篇博文[url=http://rubel.iteye.com/blog/891657]《几个文字加密的简洁算法和一些个人的想法》[/url]——字符平移法
以及上一篇博文[url=http://rubel.iteye.com/blog/897191]《几个文字加密的简洁算法(续)》[/url]——字符错位法
这里提供第三种加密方法——对字符 [b]Unicode 值[/b] 的 “进制转换” 法[/size]

[size=medium]先说点废话……

0x7a 是英文小写字母‘z’的编码值,这是编码规范规定的,机器知道,程序员也知道。
0x7a 是十进制 122——这,为什么呢? ……因为

十六进制是由 [b]0123456789abcdef[/b] 十六个字符来表达的,并且,a 代表 10、b 代表 11,以此类推。122 用十六进制转换下来就是 7a。so…… [b]单纯的进制转换其实是不能实现加密的[/b]!

但是,如果 a 不代表 10,b 不代表 11,9 代表的是 0 或其它呢——也就是说,进制表中各字符所代表的值是 [b]随机[/b] 的,不符合常规约定,那…… 7a 代表什么呢? 你无法知道,机器也不可能明白!

所以,如果指定一个字符 [b]随机排列[/b] 的进制表,依此转换字符编码值,那除非你有那个原始的进制表,否则你是无法知道 7a 是哪个字符的值(即:0x7a != 122)。

“进制乱序法”——这里,[b]随机排布的进制表就是密钥[/b]。

根据 Unicode-16 的编码规范,CJK 字符集中 20902 个汉字的编码值在 65535 以内(即 2 的 16 次方),如果用十六进制表示,每个字需要4个进制字符表达,1 变 4! 密文增加得太多了,不划算! 折中,取 3 个进制字符表达,需要 [b]41 进制[/b] 才能涵盖 65535 的码值(41*41*41 = 68921 > 65535)。

原则上,进制表字符可以采用任意 8 bit 字符,但考虑通用性,以及字符在各种网络上的正常传输,这里仅采用英文字符 [b]a-z,和 A-Z[/b],区分大小写共 [b]52 个字符[/b] 作为进制表字符候选。

注意:算法中对转换后的字符串(进制表字符)增加了“[b]平移加密[/b]”(见 [url=http://rubel.iteye.com/blog/891657]算法1 [/url]) 操作,使得加密强度更高了。[/size]

[color=blue][b][size=medium]算法3:进制乱序法[/size][/b][/color]


(function() {
//
// 进制转换-加密:
// 采用 [a-zA-Z] 52 个字符随机排列成进制表,对字符的值进行转换。
// 固定 3 位字符,41 进制,字符值最大可为 68920(> 65535)。
// 特点:
// 1. 密文为纯大小写英文字母,及原有的 [\s\n\r];
// 2. 增加了平移操作,双重加密;
// 3. key[0-40] 为进制表,逆向 16-25 位作为平移密钥;
// 4. 进制表段字符不可重复。
// 5. 空白、换行和回车 [\s\n\r] 不加密。
// 缺点:
// 密文会比原文长,单字节字符会增长得较多。
// 推荐:
// 适用于任意类型的文本加密,网络环境可采用压缩传输;
// 注意:
// key 字符串不能含非 [a-zA-Z] 字符(关联数组)。
//
// @param string key - 进制表串(length >= 41)
// @return string - 转换后的字符串
//
String.prototype._41hex = (function()
{
var _k, _k2, _sz;

return function( key ) {
if (key.length < 41) return null;

if (_k != key) {
_sz = key.charCodeAt(40) % 10 + 16,
_k2 = key.slice(-_sz).split('');
for (var _i=0; _i<_sz; ++_i) {
_k2[_i] = _k2[_i].charCodeAt(0);
}
_k = key;
}
var _cnt = 0;
return this.replace(/[^\s\n\r]/g, function(s) {
var _n = s.charCodeAt(0);
return key.charAt(parseInt(_n/1681)) + key.charAt(parseInt(_n%1681/41)) + key.charAt(_n%41);

}).replace(/[a-zA-Z]/g, function(s) {
var _n = s.charCodeAt(0),
_beg = (_n < 0x61) ? 0x41 : 0x61,
_c = _n - _beg;
return String.fromCharCode((_c+_k2[_cnt++%_sz])%26 + _beg);
});
};
})();

//
// 进制转换-解密
// @return string - 恢复后的字符串
//
String.prototype._un41hex = (function()
{
var _k, _k2 = [], _sz, _tbl = {};

return function( key ) {
if (key.length < 41) return null;

if (_k != key) {
// 逆向,防止属性值覆盖
for (var _i=key.length-1; _i>=0; --_i) {
_tbl[key.charAt(_i)] = _i;
_k2[_i] = key.charCodeAt(_i);
}
_sz = _k2[40] % 10 + 16;
_k2 = _k2.slice(-_sz);
_k = key;
}
var _cnt = 0;
return this.replace(/[a-zA-Z]/g, function(s) {
var _n = s.charCodeAt(0),
_beg = (_n < 0x61) ? 0x41 : 0x61,
_c = _n - _beg;
return String.fromCharCode((_c-_k2[_cnt++%_sz]%26+26)%26 + _beg);

}).replace(/[a-zA-Z]{3}/g, function(s) {
var _n = _tbl[s.charAt(0)]*1681 + _tbl[s.charAt(1)]*41 + _tbl[s.charAt(2)];
return String.fromCharCode(_n);
});
};
})();

})();


[b][size=medium]优化单字节字符串加密[/size][/b]
[size=medium]
——采用 2 个进制表字符,用 16 进制表达,降低密文的增长长度,仅适用于码值在 0xff 以内的字符(码值超出的字符——如中文会 [b]原样保留[/b])。
[/size]

(function() {
//
// 进制转换:单字节字符版本-加密。
// 采用 16 进制,固定 2 个字符。
// 特点:
// 值大于 0xff 的字符会原样保留,即不加密非拉丁字符。
//
// @param string key - 进制表串(length >= 16)
// @return string - 转换后的字符串
//
String.prototype._16hex = (function()
{
var _k, _k2, _sz;

return function( key ) {
if (key.length < 16) return null;

if (_k != key) {
// 加强平移密钥
_sz = key.charCodeAt(15) % (key.length-6) + 6,
_k2 = key.slice(-_sz).split('');
for (var _i=0; _i<_sz; ++_i) {
_k2[_i] = _k2[_i].charCodeAt(0);
}
_k = key;
}
var _cnt = 0;
return this.replace(/[\x21-\xff]/g, function(s) {
var _n = s.charCodeAt(0);
return key.charAt(parseInt(_n/16)) + key.charAt(_n%16);

}).replace(/[a-zA-Z]/g, function(s) {
var _n = s.charCodeAt(0),
_beg = (_n < 0x61) ? 0x41 : 0x61,
_c = _n - _beg;
return String.fromCharCode((_c+_k2[_cnt++%_sz])%26 + _beg);
});
};
})();

//
// 进制转换:单字节字符版本-解密
// @return string - 恢复后的字符串
//
String.prototype._un16hex = (function()
{
var _k, _k2 = [], _sz, _tbl = {};

return function( key ) {
if (key.length < 16) return null;

if (_k != key) {
// 逆向,防止属性值覆盖
for (var _i=key.length-1; _i>=0; --_i) {
_tbl[key.charAt(_i)] = _i;
_k2[_i] = key.charCodeAt(_i);
}
_sz = _k2[15] % (key.length-6) + 6;
_k2 = _k2.slice(-_sz);
_k = key;
}
var _cnt = 0;
return this.replace(/[a-zA-Z]/g, function(s) {
var _n = s.charCodeAt(0),
_beg = (_n < 0x61) ? 0x41 : 0x61,
_c = _n - _beg;
return String.fromCharCode((_c-_k2[_cnt++%_sz]%26+26)%26 + _beg);

}).replace(/[a-zA-Z]{2}/g, function(s) {
var _n = _tbl[s.charAt(0)]*16 + _tbl[s.charAt(1)];
return String.fromCharCode(_n);
});
};
})();

})();


[size=medium][b]用法:[/b][/size]

<script language="JavaScript">
var _str = "中文字符串和 English char string 的 JS 加密 Test. 包含一些标点符号,*@%! 等。";
// [a-zA-Z] 的随机排列
var _t = 'DsCqrtEcbFLOuijMklNmUVnwGvHopIJKxyzABaSTWPQRXdeYfhZg';
var _enc3 = _str._41hex(_t);
alert(_enc3);
alert(_enc3._un41hex(_t));
</script>


[size=medium][b]特点:[/b]
1. 密文会增长,是原始字符串长度的 3 倍(或 2 倍),但适用于各种字符集;
2. 密文是英文大小写字母,便于各类环境下的数据传输,保留空格和换行不做转换,节约编码长度;
3. 因对密文进行了平移操作,所以即便只是统计 41 进制表中包含了哪些字符也不可能(破解需要知道进制表中有哪些字符和如何排列)。[/size]

[color=blue][b]扯了好多哦…………快过节了,没事多唠唠哈哈,俺的时间不值钱……呵呵[/b][/color]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值