作者:neoma安荷
时间:2018年11月1日
来源:CSDN
1. Base58加密原理:和通常base64编码一样,base58编码的作用也是将非可视字符可视化(ASCII化)。但不同的是base58编码去掉了几个看起来会产生歧义的字符,如 0 (零), O (大写字母O), I (大写的字母i) and l (小写的字母L) ,和几个影响双击选择的字符,如/, +。结果字符集正好58个字符(包括9个数字,24个大写字母,25个小写字母)。
转载者注:由于IE8及以下版本不支持Map对象,需要换成Chrome浏览器,或者参考下面文章,重写了Map对象。
https://startbitcoin.org/8502/
2. 直接上代码(加密):
a 先存ALPHABET_MAP(方便后期检查当前是否为Base58编码)
- var ALPHABET = ‘123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz’;
- var ALPHABET_MAP = {};
- var BASE = 58;
- for (var i = 0; i < ALPHABET.length; i++) {
- ALPHABET_MAP[ALPHABET.charAt(i)] = i;
- }
- // 得到对象ALPHABET_MAP —> {1: 0, 2: 1, 3: 2, 4: 3, 5: 4, 6: 5, 7: 6, 8: 7, 9: 8, A: 9, B: 10, C: 11, D: 12, E: 13, …, y: 56, z: 57}
b 将字符串转为byte字节数组(这里用的UTF8)
- // 字符串转utf8格式的字节数组(英文和数字直接返回的acsii码,中文转%xx之后打断当成16进制转10进制)
- function ToUTF8(str) {
- var result = new Array();
- var k = 0;
- for (var i = 0; i < str.length; i++) {
- var j = encodeURI(str[i]);
- if (j.length==1) {
- // 未转换的字符
- result[k++] = j.charCodeAt(0);
- } else {
- // 转换成%XX形式的字符
- var bytes = j.split(“%”);
- for (var l = 1; l < bytes.length; l++) {
- result[k++] = parseInt(“0x” + bytes[l]);
- }
- }
- }
- return result;
- }
- // 如果有特殊需求,要转成utf16,可以用以下函数
- function ToUTF16(str) {
- var result = new Array();
- var k = 0;
- for (var i = 0; i < str.length; i++) {
- var j = str[i].charCodeAt(0);
- result[k++] = j & 0xFF;
- result[k++] = j >> 8;
- }
- return result;
- }
c Base58加密函数
- // 传进已经转成字节的数组 –>buffer(utf8格式)
- function encode(buffer) {
- if (buffer.length === 0) return ”;
- var i,
- j,
- digits = [0];
- for (i = 0; i < buffer.length; i++) {
- for (j = 0; j < digits.length; j++){
- // 将数据转为二进制,再位运算右边添8个0,得到的数转二进制
- // 位运算–>相当于 digits[j].toString(2);parseInt(10011100000000,2)
- digits[j] <<= 8;
- }
- digits[0] += buffer[i];
- var carry = 0;
- for (j = 0; j < digits.length; ++j) {
- digits[j] += carry;
- carry = (digits[j] / BASE) | 0;
- digits[j] %= BASE;
- }
- while (carry) {
- digits.push(carry % BASE);
- carry = (carry / BASE) | 0;
- }
- }
- // deal with leading zeros
- for (i = 0; buffer[i] === 0 && i < buffer.length – 1; i++) digits.push(0);
- return digits
- .reverse()
- .map(function(digit) {
- return ALPHABET[digit];
- })
- .join(”);
- }
- // ToUTF8(‘6嘎’) —>[54, 229, 152, 142]
- // encode(ToUTF8(‘6嘎’)) —> 2QPT7B
- console.log(encode(ToUTF8(‘6嘎’)))
3 直接上代码(解密):
a 解密成字节数组
- // string —> 加密后的字符串
- function decode(string) {
- if (string.length === 0) return [];
- var i,
- j,
- bytes = [0];
- for (i = 0; i < string.length; i++) {
- var c = string[i];
- // c是不是ALPHABET_MAP的key
- if (!(c in ALPHABET_MAP)) throw new Error(‘Non-base58 character’);
- for (j = 0; j < bytes.length; j++) bytes[j] *= BASE;
- bytes[0] += ALPHABET_MAP[c];
- var carry = 0;
- for (j = 0; j < bytes.length; ++j) {
- bytes[j] += carry;
- carry = bytes[j] >> 8;
- // 0xff –> 11111111
- bytes[j] &= 0xff;
- }
- while (carry) {
- bytes.push(carry & 0xff);
- carry >>= 8;
- }
- }
- // deal with leading zeros
- for (i = 0; string[i] === ‘1’ && i < string.length – 1; i++) bytes.push(0);
- return bytes.reverse();
- }
- // [54, 229, 152, 142]
- console.log(decode(2QPT7B))
b 将字节数组解密成字符串
- // 传字节数组
- function byteToString(arr) {
- if (typeof arr === ‘string’) {
- return arr;
- }
- var str = ”,
- _arr = arr;
- for (var i = 0; i < _arr.length; i++) {
- // 数组中每个数字转为二进制 匹配出开头为1的直到0的字符
- // eg:123–>”1111011″–>{0:”1111″,groups: undefined, index: 0, input: “1111011”}
- var one = _arr[i].toString(2),
- v = one.match(/^1+?(?=0)/);
- if (v && one.length == 8) {
- var bytesLength = v[0].length;
- var store = _arr[i].toString(2).slice(7 – bytesLength);
- for (var st = 1; st < bytesLength; st++) {
- store += _arr[st + i].toString(2).slice(2);
- }
- str += String.fromCharCode(parseInt(store, 2));
- i += bytesLength – 1;
- } else {
- str += String.fromCharCode(_arr[i]);
- }
- }
- return str;
- }
- // 6嘎
- console.log([54, 229, 152, 142])