基于Java实现的Base64加密、解密原理代码
一、概述
1.Base64是什么:
Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在JavaPersistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTPGETURL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到
2.简介:
标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSISQL中已将“%”号用作通配符。
为解决此问题,可采用一种用于URL的改进Base64编码,它不在末尾填充'='号,并将标准Base64中的“+”和“/”分别改成了“*”和“-”,这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。
另有一种用于正则表达式的改进Base64变种,它将“+”和“/”改成了“!”和“-”,因为“+”,“*”以及前面在IRCu中用到的“[”和“]”在正则表达式中都可能具有特殊含义。
此外还有一些变种,它们将“+/”改为“_-”或“._”(用作编程语言中的标识符名称)或“.-”(用于XML中的Nmtoken)甚至“_:”(用于XML中的Name)。
Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8=4*6=24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
3.规则:
关于这个编码的规则:
①.把3个字符变成4个字符..
②.每76个字符加一个换行符..
③.最后的结束符也要处理..
这样说会不会太抽象了?不用着急,我们来看一个例子:
转换前:aaaaaabbccccddddeeffffff
转换后:00aaaaaa00bbcccc00ddddee00ffffff
应该很清楚了吧?上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。
转换后,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码)
二、java实现代码示例:
publicfinalclassBase64{
staticprivatefinalintBASELENGTH=255;
staticprivatefinalintLOOKUPLENGTH=64;
staticprivatefinalintTWENTYFOURBITGROUP=24;
staticprivatefinalintEIGHTBIT=8;
staticprivatefinalintSIXTEENBIT=16;
staticprivatefinalintSIXBIT=6;
staticprivatefinalintFOURBYTE=4;
staticprivatefinalintSIGN=-128;
staticprivatefinalcharPAD='=';
staticprivatefinalbooleanfDebug=false;
staticfinalprivatebyte[]base64Alphabet=newbyte[BASELENGTH];
staticfinalprivatechar[]lookUpBase64Alphabet=newchar[LOOKUPLENGTH];
static{
for(inti=0;i<BASELENGTH;i++){
base64Alphabet[i]=-1;
}
for(inti='Z';i>='A';i--){
base64Alphabet[i]=(byte)(i-'A');
}
for(inti='z';i>='a';i--){
base64Alphabet[i]=(byte)(i-'a'+26);
}
for(inti='9';i>='0';i--){
base64Alphabet[i]=(byte)(i-'0'+52);
}
base64Alphabet['+']=62;
base64Alphabet['/']=63;
for(inti=0;i<=25;i++)
lookUpBase64Alphabet[i]=(char)('A'+i);
for(inti=26,j=0;i<=51;i++,j++)
lookUpBase64Alphabet[i]=(char)('a'+j);
for(inti=52,j=0;i<=61;i++,j++)
lookUpBase64Alphabet[i]=(char)('0'+j);
lookUpBase64Alphabet[62]=(char)'+';
lookUpBase64Alphabet[63]=(char)'/';
}
protectedstaticbooleanisWhiteSpace(charoctect){
return(octect==0x20||octect==0xd||octect==0xa||octect==0x9);
}
protectedstaticbooleanisPad(charoctect){
return(octect==PAD);
}
protectedstaticbooleanisData(charoctect){
return(base64Alphabet[octect]!=-1);
}
protectedstaticbooleanisBase64(charoctect){
return(isWhiteSpace(octect)||isPad(octect)||isData(octect));
}
/**
*EncodeshexoctectsintoBase64
*
*@parambinaryData
*ArraycontainingbinaryData
*@returnEncodedBase64array
*/
publicstaticStringencode(byte[]binaryData){
if(binaryData==null)
returnnull;
intlengthDataBits=binaryData.length*EIGHTBIT;
if(lengthDataBits==0){
return"";
}
intfewerThan24bits=lengthDataBits%TWENTYFOURBITGROUP;
intnumberTriplets=lengthDataBits/TWENTYFOURBITGROUP;
intnumberQuartet=fewerThan24bits!=0?numberTriplets+1
:numberTriplets;
intnumberLines=(numberQuartet-1)/19+1;
charencodedData[]=null;
encodedData=newchar[numberQuartet*4+numberLines];
bytek=0,l=0,b1=0,b2=0,b3=0;
intencodedIndex=0;
intdataIndex=0;
inti=0;
if(fDebug){
System.out.println("numberoftriplets="+numberTriplets);
}
for(intline=0;line<numberLines-1;line++){
for(intquartet=0;quartet<19;quartet++){
b1=binaryData[dataIndex++];
b2=binaryData[dataIndex++];
b3=binaryData[dataIndex++];
if(fDebug){
System.out.println("b1="+b1+",b2="+b2+",b3="
+b3);
}
l=(byte)(b2&0x0f);
k=(byte)(b1&0x03);
byteval1=((b1&SIGN)==0)?(byte)(b1>>2)
:(byte)((b1)>>2^0xc0);
byteval2=((b2&SIGN)==0)?(byte)(b2>>4)
:(byte)((b2)>>4^0xf0);
byteval3=((b3&SIGN)==0)?(byte)(b3>>6)
:(byte)((b3)>>6^0xfc);
if(fDebug){
System.out.println("val2="+val2);
System.out.println("k4="+(k<<4));
System.out.println("vak="+(val2|(k<<4)));
}
encodedData[encodedIndex++]=lookUpBase64Alphabet[val1];
encodedData[encodedIndex++]=lookUpBase64Alphabet[val2
|(k<<4)];
encodedData[encodedIndex++]=lookUpBase64Alphabet[(l<<2)
|val3];
encodedData[encodedIndex++]=lookUpBase64Alphabet[b3&0x3f];
i++;
}
encodedData[encodedIndex++]=0xa;
}
for(;i<numberTriplets;i++){
b1=binaryData[dataIndex++];
b2=binaryData[dataIndex++];
b3=binaryData[dataIndex++];
if(fDebug){
System.out.println("b1="+b1+",b2="+b2+",b3="+b3);
}
l=(byte)(b2&0x0f);
k=(byte)(b1&0x03);
byteval1=((b1&SIGN)==0)?(byte)(b1>>2)
:(byte)((b1)>>2^0xc0);
byteval2=((b2&SIGN)==0)?(byte)(b2>>4)
:(byte)((b2)>>4^0xf0);
byteval3=((b3&SIGN)==0)?(byte)(b3>>6)
:(byte)((b3)>>6^0xfc);
if(fDebug){
System.out.println("val2="+val2);
System.out.println("k4="+(k<<4));
System.out.println("vak="+(val2|(k<<4)));
}
encodedData[encodedIndex++]=lookUpBase64Alphabet[val1];
encodedData[encodedIndex++]=lookUpBase64Alphabet[val2|(k<<4)];
encodedData[encodedIndex++]=lookUpBase64Alphabet[(l<<2)|val3];
encodedData[encodedIndex++]=lookUpBase64Alphabet[b3&0x3f];
}
//formintegralnumberof6-bitgroups
if(fewerThan24bits==EIGHTBIT){
b1=binaryData[dataIndex];
k=(byte)(b1&0x03);
if(fDebug){
System.out.println("b1="+b1);
System.out.println("b1<<2="+(b1>>2));
}
byteval1=((b1&SIGN)==0)?(byte)(b1>>2)
:(byte)((b1)>>2^0xc0);
encodedData[encodedIndex++]=lookUpBase64Alphabet[val1];
encodedData[encodedIndex++]=lookUpBase64Alphabet[k<<4];
encodedData[encodedIndex++]=PAD;
encodedData[encodedIndex++]=PAD;
}elseif(fewerThan24bits==SIXTEENBIT){
b1=binaryData[dataIndex];
b2=binaryData[dataIndex+1];
l=(byte)(b2&0x0f);
k=(byte)(b1&0x03);
byteval1=((b1&SIGN)==0)?(byte)(b1>>2)
:(byte)((b1)>>2^0xc0);
byteval2=((b2&SIGN)==0)?(byte)(b2>>4)
:(byte)((b2)>>4^0xf0);
encodedData[encodedIndex++]=lookUpBase64Alphabet[val1];
encodedData[encodedIndex++]=lookUpBase64Alphabet[val2|(k<<4)];
encodedData[encodedIndex++]=lookUpBase64Alphabet[l<<2];
encodedData[encodedIndex++]=PAD;
}
encodedData[encodedIndex]=0xa;
returnnewString(encodedData);
}
/**
*DecodesBase64dataintooctects
*
*@parambinaryData
*BytearraycontainingBase64data
*@returnArraycontaininddecodeddata.
*/
publicstaticbyte[]decode(Stringencoded){
if(encoded==null)
returnnull;
char[]base64Data=encoded.toCharArray();
//removewhitespaces
intlen=removeWhiteSpace(base64Data);
if(len%FOURBYTE!=0){
returnnull;//shouldbedivisiblebyfour
}
intnumberQuadruple=(len/FOURBYTE);
if(numberQuadruple==0)
returnnewbyte[0];
bytedecodedData[]=null;
byteb1=0,b2=0,b3=0,b4=0,marker0=0,marker1=0;
chard1=0,d2=0,d3=0,d4=0;
inti=0;
intencodedIndex=0;
intdataIndex=0;
decodedData=newbyte[(numberQuadruple)*3];
for(;i<numberQuadruple-1;i++){
if(!isData((d1=base64Data[dataIndex++]))
||!isData((d2=base64Data[dataIndex++]))
||!isData((d3=base64Data[dataIndex++]))
||!isData((d4=base64Data[dataIndex++])))
returnnull;//iffound"nodata"justreturnnull
b1=base64Alphabet[d1];
b2=base64Alphabet[d2];
b3=base64Alphabet[d3];
b4=base64Alphabet[d4];
decodedData[encodedIndex++]=(byte)(b1<<2|b2>>4);
decodedData[encodedIndex++]=(byte)(((b2&0xf)<<4)|((b3>>2)&0xf));
decodedData[encodedIndex++]=(byte)(b3<<6|b4);
}
if(!isData((d1=base64Data[dataIndex++]))
||!isData((d2=base64Data[dataIndex++]))){
returnnull;//iffound"nodata"justreturnnull
}
b1=base64Alphabet[d1];
b2=base64Alphabet[d2];
d3=base64Data[dataIndex++];
d4=base64Data[dataIndex++];
if(!isData((d3))||!isData((d4))){//CheckiftheyarePADcharacters
if(isPad(d3)&&isPad(d4)){//TwoPADe.g.3c[Pad][Pad]
if((b2&0xf)!=0)//last4bitsshouldbezero
returnnull;
byte[]tmp=newbyte[i*3+1];
System.arraycopy(decodedData,0,tmp,0,i*3);
tmp[encodedIndex]=(byte)(b1<<2|b2>>4);
returntmp;
}elseif(!isPad(d3)&&isPad(d4)){//OnePADe.g.3cQ[Pad]
b3=base64Alphabet[d3];
if((b3&0x3)!=0)//last2bitsshouldbezero
returnnull;
byte[]tmp=newbyte[i*3+2];
System.arraycopy(decodedData,0,tmp,0,i*3);
tmp[encodedIndex++]=(byte)(b1<<2|b2>>4);
tmp[encodedIndex]=(byte)(((b2&0xf)<<4)|((b3>>2)&0xf));
returntmp;
}else{
returnnull;//anerrorlike"3c[Pad]r","3cdX","3cXd","3cXX"
//whereXisnondata
}
}else{//NoPADe.g3cQl
b3=base64Alphabet[d3];
b4=base64Alphabet[d4];
decodedData[encodedIndex++]=(byte)(b1<<2|b2>>4);
decodedData[encodedIndex++]=(byte)(((b2&0xf)<<4)|((b3>>2)&0xf));
decodedData[encodedIndex++]=(byte)(b3<<6|b4);
}
returndecodedData;
}
/**
*removeWhiteSpacefromMIMEcontainingencodedBase64data.
*
*@paramdata
*thebytearrayofbase64data(withWS)
*@returnthenewlength
*/
protectedstaticintremoveWhiteSpace(char[]data){
if(data==null)
return0;
//countcharactersthat'snotwhitespace
intnewSize=0;
intlen=data.length;
for(inti=0;i<len;i++){
if(!isWhiteSpace(data[i]))
data[newSize++]=data[i];
}
returnnewSize;
}
publicstaticvoidmain(String[]args){
System.out.println(encode("中华人民共和国".getBytes()));
}
}