从IE10+浏览器开始,所有浏览器就原生提供了Base64编码、解码方法,不仅可以用于浏览器环境,Service Worker环境也可以使用。
方法名就是 atob 和 btoa ,具体语法如下:
IE8/IE9的polyfill
当下,仍有不少PC项目还需要兼容IE9,所以,我们可以专门针对这些浏览器再引入一段ployfill脚本或者一个JS文件即可。
[if IE] 表示所有IE浏览器,由于IE10+浏览器已经放弃了著名的IE条件注释的支持,Chrome等浏览器本身就不支持这个IE私有语法,因此,很天然的,上面一段script引入只在IE9-浏览器下有效。而我们本来就希望只IE8,IE9浏览器引入ployfill,于是正好完美衔接上。
也就是原生支持atob和btoa方法的浏览器认为就是一段无需关心的HTML注释,不支持atob和btoa的IE9及其以下浏览器则会加载我们的base64-polyfill.js,使浏览器也支持 window.btoa 和 window.atob 这个语法。
开源的 base64.js ,使用很简单,浏览器引入该JS文件,然后Base64编码这样:
解码就调用 decode 方法,如下:
Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,在发送电子邮件时,服务器认证的用户名和密码需要用Base64编码,附件也需要用Base64编码。
下面简单介绍Base64算法的原理,由于代码太长就不在此贴出
Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
转换后,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码),这个表是这样的:
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
原文的字节最后不够3个的地方用0来补足,转换时Base64编码用=号来代替。这就是为什么有些Base64编码会以一个或两个等号结束的原因,但等号最多只有两个。
举一个例子,abc经过Base64编码以后的结果是YWJj.
发邮件的时候所写的信息自动在后台转换然后传输...
参考资料:
string str = "张利峰";
string encodestr = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(str));
string decodestr = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(encodestr));
关于这个编码的规则:
①.把3个字符变成4个字符..
②每76个字符加一个换行符..
③.最后的结束符也要处理..
对于①就是 4个字符32位..有个字符..24位...相差8个位..这8个位..会平均分给每个字节的高两位..则好2*4 = 8.吗...
下面是我用C++实现的...带有注释...通过移位操作实现的...对移位操作不熟悉的朋友可能有点吃力了...
void base642(char * string ,char * pch)
{
int i = 0;
BYTE b1 ,b2 ,b3;
CAtlStringA str(string);
int len = str.GetLength();
char b;
do
{
//
b1 = string[i++];
//b1 右移2位..高2位清0...
//b1.剩下2位要放在第2个字符中..
b = BASE64TABLE[b12];
//得到第1个字符..
*pch ++ = b;
//判断是不是该换行了..76个字符要换行.放在这里..避免i=1的时候换行..
if(i % 76 == 0)
{
*pch ++ = '\r';
*pch ++ = '\n';
}
b2 = string[i++];
//(b1的最后2位要放在b2的第6位(7.8两位要填充0))b1.要左移4位... b2 右移4位...然后相加..在把最高2位清0..
//b2.剩下4位.要放在第3个字符中...
b = BASE64TABLE[((b1 4) + (b2 4)) (0x3f)];
//得到第2个字符..
*pch ++ = b;
//如果没有第3个字符了..那就停止循环了..
////这里不能是= ...因为还要处理最后一个0x00结束符..len不包含最后结束符...
if(i len)
break;//①
b3 = (BYTE) string[i++];
//b2的4位要放在第3个字符的第6位...b2.要左移2位...b3要右移6位..高2位放在此字符的最后两位..
//b3 就剩下了6个字符...
b = BASE64TABLE[((b2 2) + (b3 6)) (0x3f)];
*pch ++ = b;
//如果超过了.就停止了吧..
if(i len)
break;//②
///b3高2位清0 .就可以得到第4个字符...
b = BASE64TABLE[b3 (0x3f)];
*pch ++ = b;
}while(i len);
//取得余数..
int residue = len % 3;
///判断最后要加几个=号..
int y = (residue == 1) ? 2 : (residue == 2 ? 1 : 0) ;
for(int i = 0;i y ;i++)
*pch++ = '=';
/*
这个算法...当中的break.总是感觉会丢失位...
但是仔细一想.最后一字符是0x00....丢失了..也不要紧..
假设有1个字符.. 加上一个结束符..实际上是两个字符..到①这个位置会break...丢失了4位...这4位全部是0..
假设有2个字符..加上一个结束符..实际上是三个字符.到②这个位置会break..丢失6位..同伴全部是0..
假设有3个字符...刚好处理完毕...最后一个结束符..不会处理了...
*/
}
void base642(char * string ,char * pch)
{
int i = 0;
BYTE b1 ,b2 ,b3;
CAtlStringA str(string);
int len = str.GetLength();
char b;
do
{
//
b1 = string[i++];
//b1 右移2位..高2位清0...
//b1.剩下2位要放在第2个字符中..
b = BASE64TABLE[b12];
//得到第1个字符..
*pch ++ = b;
//判断是不是该换行了..76个字符要换行.放在这里..避免i=1的时候换行..
if(i % 76 == 0)
{
*pch ++ = '\r';
*pch ++ = '\n';
}
b2 = string[i++];
//(b1的最后2位要放在b2的第6位(7.8两位要填充0))b1.要左移4位... b2 右移4位...然后相加..在把最高2位清0..
//b2.剩下4位.要放在第3个字符中...
b = BASE64TABLE[((b1 4) + (b2 4)) (0x3f)];
//得到第2个字符..
*pch ++ = b;
//如果没有第3个字符了..那就停止循环了..
////这里不能是= ...因为还要处理最后一个0x00结束符..len不包含最后结束符...
if(i len)
break;//①
b3 = (BYTE) string[i++];
//b2的4位要放在第3个字符的第6位...b2.要左移2位...b3要右移6位..高2位放在此字符的最后两位..
//b3 就剩下了6个字符...
b = BASE64TABLE[((b2 2) + (b3 6)) (0x3f)];
*pch ++ = b;
//如果超过了.就停止了吧..
if(i len)
break;//②
///b3高2位清0 .就可以得到第4个字符...
b = BASE64TABLE[b3 (0x3f)];
*pch ++ = b;
}while(i len);
//取得余数..
int residue = len % 3;
///判断最后要加几个=号..
int y = (residue == 1) ? 2 : (residue == 2 ? 1 : 0) ;
for(int i = 0;i y ;i++)
*pch++ = '=';
/*
这个算法...当中的break.总是感觉会丢失位...
但是仔细一想.最后一字符是0x00....丢失了..也不要紧..
假设有1个字符.. 加上一个结束符..实际上是两个字符..到①这个位置会break...丢失了4位...这4位全部是0..
假设有2个字符..加上一个结束符..实际上是三个字符.到②这个位置会break..丢失6位..同伴全部是0..
假设有3个字符...刚好处理完毕...最后一个结束符..不会处理了...
*/
}
这个是解码的函数.
view plaincopy to clipboardprint?
void base644(char * string ,char * pch)
{
CAtlStringA tab("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
CAtlStringA str(string);
str.Remove('=');
str.Remove('\r');
str.Remove('\n');
int len = str.GetLength();
int i = 0;
BYTE b1 ,b2 ,b3 ,b4;
char ch;
do
{
//找字符1的位置.
b1 = tab.Find((str[i++]));
//找字符2的位置.
b2 = tab.Find((str[i++]));
//b1左移两位..还原.此时少了最后两位...b2的第6位和第5位..要右移4位(变成最后两位.)..此时和b1相加...即可
//b1还原...
ch = (b1 2) + (b2 4);
//得到此字节..
*pch ++ = ch;
//超过了..break吧..这是要有这个=号...当=成立的时候.表明已经是最后一个字符了...后面不要处理..
if(i = len)
break;
//取第3个字符..的位置
b3 = tab.Find((str[i++]));
//从这里开始判断..因为=号最多有两个...换行是额外加的..所以编码后有效的字符至少为2个..
//还原第2个字符...b2中有b1的两个位..所以b2左移4位..即可把b1的两个位和00两个最高位去除..b2中只有
//有效的4个位..b3中还有4个位....b3右移2位..即可把5位6位变成低4位..因为要相加的..
ch = (b2 4) + (b3 2);
*pch ++ = ch;
//超过了..break吧.
if(i = len)
break;
//找第4个字符..
b4 = tab.Find((str[i++]));
//还原第3个字符...b3中有两个位...要放在最高两位...所以左移6位..加上b4即可..(b4的高两位为0..)
ch = (b3 6) + b4;
*pch ++ = ch;
}
while(i len);
////最后加个结束符...
*pch =0x00;
}
void base644(char * string ,char * pch)
{
CAtlStringA tab("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
CAtlStringA str(string);
str.Remove('=');
str.Remove('\r');
str.Remove('\n');
int len = str.GetLength();
int i = 0;
BYTE b1 ,b2 ,b3 ,b4;
char ch;
do
{
//找字符1的位置.
b1 = tab.Find((str[i++]));
//找字符2的位置.
b2 = tab.Find((str[i++]));
//b1左移两位..还原.此时少了最后两位...b2的第6位和第5位..要右移4位(变成最后两位.)..此时和b1相加...即可
//b1还原...
ch = (b1 2) + (b2 4);
//得到此字节..
*pch ++ = ch;
//超过了..break吧..这是要有这个=号...当=成立的时候.表明已经是最后一个字符了...后面不要处理..
if(i = len)
break;
//取第3个字符..的位置
b3 = tab.Find((str[i++]));
//从这里开始判断..因为=号最多有两个...换行是额外加的..所以编码后有效的字符至少为2个..
//还原第2个字符...b2中有b1的两个位..所以b2左移4位..即可把b1的两个位和00两个最高位去除..b2中只有
//有效的4个位..b3中还有4个位....b3右移2位..即可把5位6位变成低4位..因为要相加的..
ch = (b2 4) + (b3 2);
*pch ++ = ch;
//超过了..break吧.
if(i = len)
break;
//找第4个字符..
b4 = tab.Find((str[i++]));
//还原第3个字符...b3中有两个位...要放在最高两位...所以左移6位..加上b4即可..(b4的高两位为0..)
ch = (b3 6) + b4;
*pch ++ = ch;
}
while(i len);
////最后加个结束符...
*pch =0x00;
}
//下面是测试程序.
view plaincopy to clipboardprint?
int _tmain(int argc, _TCHAR* argv[])
{
char pch[0x1dc]={0};
CAtlStringA str("谢谢你啊" );
CStrBufA buf(str);
base642(CStrBufA::PXSTR(buf),pch);
cout pchendl;
cout "********************************************************************************"endl;
CAtlStringA str2 = "0LvQu8TjsKE=";
CStrBufA buf2(str2);
RtlZeroMemory(pch ,0x1dc);
base644(CStrBufA::PXSTR(buf2) ,pch);
cout pchendl;
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
char pch[0x1dc]={0};
CAtlStringA str("谢谢你啊" );
CStrBufA buf(str);
base642(CStrBufA::PXSTR(buf),pch);
cout pchendl;
cout "********************************************************************************"endl;
CAtlStringA str2 = "0LvQu8TjsKE=";
CStrBufA buf2(str2);
RtlZeroMemory(pch ,0x1dc);
base644(CStrBufA::PXSTR(buf2) ,pch);
cout pchendl;
return 0;
}
用到的数组.
const char BASE64TABLE[64]={
'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b',
'c','d','e','f','g','h','i','j','k','l','m','n','o','p',
'q','r','s','t','u','v','w','x','y','z','0','1','2','3',
'4','5','6','7','8','9','+','/'
};
这个作用就是....26刚好64...base64会计算每个字符的6位...然后从这个表中选中一个字母.作为最后的编码...base64当中没有其它的字符了...
如果字符数不是3的倍数..就相应的加上=号..最多有两个等号了..纯粹是为了凑数...
上面是C的,下面是C++的:
#include string
using namespace std;
class ZBase64
{
public:
/*编码
DataByte
[in]输入的数据长度,以字节为单位
*/
string Encode(const unsigned char* Data,int DataByte);
/*解码
DataByte
[in]输入的数据长度,以字节为单位
OutByte
[out]输出的数据长度,以字节为单位,请不要通过返回值计算
输出数据的长度
*/
string Decode(const char* Data,int DataByte,int OutByte);
};
#include "stdAfx.h"
#include "ZBase64.h"
string ZBase64::Encode(const unsigned char* Data,int DataByte)
{
//编码表
const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//返回值
string strEncode;
unsigned char Tmp[4]={0};
int LineLength=0;
for(int i=0;i(int)(DataByte / 3);i++)
{
Tmp[1] = *Data++;
Tmp[2] = *Data++;
Tmp[3] = *Data++;
strEncode+= EncodeTable[Tmp[1] 2];
strEncode+= EncodeTable[((Tmp[1] 4) | (Tmp[2] 4)) 0x3F];
strEncode+= EncodeTable[((Tmp[2] 2) | (Tmp[3] 6)) 0x3F];
strEncode+= EncodeTable[Tmp[3] 0x3F];
if(LineLength+=4,LineLength==76) {strEncode+="\r\n";LineLength=0;}
}
//对剩余数据进行编码
int Mod=DataByte % 3;
if(Mod==1)
{
Tmp[1] = *Data++;
strEncode+= EncodeTable[(Tmp[1] 0xFC) 2];
strEncode+= EncodeTable[((Tmp[1] 0x03) 4)];
strEncode+= "==";
}
else if(Mod==2)
{
Tmp[1] = *Data++;
Tmp[2] = *Data++;
strEncode+= EncodeTable[(Tmp[1] 0xFC) 2];
strEncode+= EncodeTable[((Tmp[1] 0x03) 4) | ((Tmp[2] 0xF0) 4)];
strEncode+= EncodeTable[((Tmp[2] 0x0F) 2)];
strEncode+= "=";
}
return strEncode;
}
string ZBase64::Decode(const char* Data,int DataByte,int OutByte)
{
//解码表
const char DecodeTable[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62, // '+'
0, 0, 0,
63, // '/'
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
0, 0, 0, 0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
0, 0, 0, 0, 0, 0,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
};
//返回值
string strDecode;
int nValue;
int i= 0;
while (i DataByte)
{
if (*Data != '\r' *Data!='\n')
{
nValue = DecodeTable[*Data++] 18;
nValue += DecodeTable[*Data++] 12;
strDecode+=(nValue 0x00FF0000) 16;
OutByte++;
if (*Data != '=')
{
nValue += DecodeTable[*Data++] 6;
strDecode+=(nValue 0x0000FF00) 8;
OutByte++;
if (*Data != '=')
{
nValue += DecodeTable[*Data++];
strDecode+=nValue 0x000000FF;
OutByte++;
}
}
i += 4;
}
else// 回车换行,跳过
{
Data++;
i++;
}
}
return strDecode;
}
使用示例(结合CxImage库):
CString CScanDlg::EncodeImage()
{//对图片进行Base64编码
ZBase64 zBase;
//图片编码
CxImage image; // 定义一个CxImage对象
image.Load(this-m_strImgPath, CXIMAGE_FORMAT_JPG); //先装载jpg文件,需要指定文件类型
long size=0;//得到图像大小
BYTE* buffer=0;//存储图像数据的缓冲
image.Encode(buffer,size,CXIMAGE_FORMAT_JPG);//把image对象中的图像以type类型数据copy到buffer
string strTmpResult=zBase.Encode(buffer,size);
CString result;
result = strTmpResult.c_str();
return result;
}
void CScanDlg::DecodeImageData(CString strData)
{//对Base64编码过的数据解码并显示原图片
ZBase64 zBase;
int OutByte=0;
string strTmpResult=zBase.Decode(strData,strData.GetLength(),OutByte);
int i,len = strTmpResult.length();
BYTE *buffer = new BYTE[len];
for (i=0;ilen;++i)
{
buffer[i] = strTmpResult[i];
}
CxImage image(buffer,len,CXIMAGE_FORMAT_JPG);//把内存缓冲buffer中的数据构造成Image对象
delete [] buffer;
CDC* hdc = m_picture.GetDC();
m_bitmap = image.MakeBitmap(hdc-m_hDC);
HBITMAP h0ldBmp = m_picture.SetBitmap(m_bitmap);
if(h0ldBmp) DeleteObject(h0ldBmp);
if(hdc-m_hDC) m_picture.ReleaseDC(hdc);
if(m_bitmap) DeleteObject(m_bitmap);
}
你自己调试一下deCode要解密的数据串,这个串的长度应该是4的倍数,否则肯定是会报这个错误的
求采纳