Base64编码将3个Byte共24Bit从高到低重新拆分成4部分每部分6Bit,分别为0x0~0x3f,对应字符为A~Z和a~z和0-9和+/,共64个。如果最后剩余1个Byte,则将其编码为2个6Bit的Base64编码(第二个Base64编码仅2Bit,需在其后面添加4Bit的0),再在末尾添加2个=字符;如果最后剩余2个Byte,则将其编码为3个6Bit的Base64编码(第三个Base64编码仅4Bit,需在其后面添加2Bit的0),再在末尾添加1个=字符。
Base64解码的方法与编码相反,将4个Base64编码字符转换为对应的0x0~0x3f,共24Bit,然后重新拆分成3部分,每部分8Bit,即1Byte,若末尾有=字符,则按编码方法中描述的规则反向处理。
Base64在谷歌、火狐浏览器都已经实现,调用方式很简单,window.atob是解码函数,把Base64编码转成字符串。window.btoa是编码函数,把字符串编码成Base64。不过谷歌和火狐浏览器实现的base64编码不支持中文,如果输入中文字符串会提示The string to be encoded contains characters outside of the Latin1 range。
IE浏览器中没有内置Base64编码函数,不过网上有很多Base64的JavaScript实现。在众多Base64编码实现中,CryptoJS是最高效和全面的,CryptosJS是一个标准和安全的JavaScript加密算法库,实现了MD5、SHA、AES、DES、Base64等加密,其代码放在Google上托管,项目地址是https://code.google.com/p/crypto-js/。当然CryptoJS的Base64对中文也没有很好的支持。
由于我的Base64编码有中文数据,所以自己实现了一个可以支持中文的方法。思路是在字符编码以前先用escape()转成非中文字符再进行编码,解码时用unescape()即可得到原来的字符。
(function(window){
var base64 = {};
base64.map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
base64.decode = function(s){
s += '';
var len = s.length;
if((len === 0) || (len % 4 !== 0)){
return s;
}
var pads = 0;
if(s.charAt(len - 1) === base64.map[64]){
pads++;
if(s.charAt(len - 2) === base64.map[64]){
pads++;
}
len -= 4;
}
var i, b, map = base64.map, x = [];
for(i = 0; i < len; i += 4){
b = (map.indexOf(s.charAt(i)) << 18) | (map.indexOf(s.charAt(i + 1)) << 12) | (map.indexOf(s.charAt(i + 2)) << 6) | map.indexOf(s.charAt(i + 3));
x.push(String.fromCharCode(b >> 16, (b >> 8) & 0xff, b & 0xff));
}
switch(pads){
case 1:
b = (map.indexOf(s.charAt(i)) << 18) | (map.indexOf(s.charAt(i)) << 12) | (map.indexOf(s.charAt(i)) << 6);
x.push(String.fromCharCode(b >> 16, (b >> 8) & 0xff));
break;
case 2:
b = (map.indexOf(s.charAt(i)) << 18) | (map.indexOf(s.charAt(i)) << 12);
x.push(String.fromCharCode(b >> 16));
break;
}
return unescape(x.join(''));
};
base64.encode = function(s){
if(!s){
return;
}
s += '';
if(s.length === 0){
return s;
}
s = escape(s);
var i, b, x = [], map = base64.map, padchar = map[64];
var len = s.length - s.length % 3;
for(i = 0; i < len; i += 3){
b = (s.charCodeAt(i) << 16) | (s.charCodeAt(i+1) << 8) | s.charCodeAt(i+2);
x.push(map.charAt(b >> 18));
x.push(map.charAt((b >> 12) & 0x3f));
x.push(map.charAt((b >> 6) & 0x3f));
x.push(map.charAt(b & 0x3f));
}
switch(s.length - len){
case 1:
b = s.charCodeAt(i) << 16;
x.push(map.charAt(b >> 18) + map.charAt((b >> 12) & 0x3f) + padchar + padchar);
break;
case 2:
b = (s.charCodeAt(i) << 16) | (s.charCodeAt(i + 1) << 8);
x.push(map.charAt(b >> 18) + map.charAt((b >> 12) & 0x3f) + map.charAt((b >> 6) & 0x3f) + padchar);
break;
}
return x.join('');
};
window.base64 = base64;
})(window);