Base64是⽹络上最常见的⽤于传输8Bit字节代码的编码⽅式之
Base64是⽹络上最常见的⽤于传输8Bit 的编码⽅式之⼀,⼤家可以查看RFC2045~RFC2049,上⾯有MIME的详细规范。Base64编码可⽤于在 环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采⽤了Base64来将⼀个较长的唯⼀ (⼀般为128-bit的UUID)编码为⼀个字符串,⽤作HTTP 和HTTP GET URL中的参数。在其他应⽤程序中,也常常需要把⼆进制 为适合放在URL(包括隐藏 )中的形式。此时,采⽤Base64编码具有不可读性,即所编码的数据不会被⼈⽤⾁眼所直接看到。
外⽂名
base64
属    性
编码⽅式
应    ⽤
⽤于传输8Bit
定    义
8Bit 的编码⽅式之⼀
可⽤于
在 环境下传递较长的标识信息
特    性
Base64编码具有不可读性
Base64编码可⽤于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采⽤了Base64来将⼀个较长的唯⼀ (⼀般为128-bit的UUID)编码为⼀个字符串,⽤作HTTP表单和HTTP GET URL中的参数。在其他应⽤程序中,也常常需要把⼆进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采⽤Base64编码不仅⽐较简短,同时也具有不可读性,即所编码的数据不会被⼈⽤⾁眼所直接看到。
然⽽,标准的Base64并不适合直接放在URL⾥传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,⽽这些“%”号在存⼊数据库时还需要再进⾏转换,因为ANSI SQL中已将“%”号⽤作通配符。
为解决此问题,可采⽤⼀种⽤于URL的改进Base64编码,它不仅在末尾填充'='号,并将标准Base64中的“+”和“/”分别改成
了“-”和“_”,这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统⼀了数据库、表单等处对象 的格式。
在线url网址编码解码另有⼀种⽤于正则表达式的改进Base64变种,它将“+”和“/”改成了“!”和“-”,因为“+”,“*”以及前⾯在IRCu中⽤到
的“[”和“]”在正则表达式中都可能具有特殊含义。
此外还有⼀些变种,它们将“+/”改为“_-”或“._”(⽤作编程语⾔中的标识符名称)或“.-”(⽤于XML中的Nmtoken)甚
⾄“_:”(⽤于XML中的Name)。
其他应⽤
Mozilla Thunderbird和Evolution⽤Base64来保密电⼦邮件密码
Base64 也会经常⽤作⼀个简单的“加密”来保护某些数据,⽽真正的加密通常都⽐较繁琐。
垃圾讯息传播者⽤Base64来避过反垃圾邮件⼯具,因为那些⼯具通常都不会翻译Base64的讯息。
在LDIF档案,Base64⽤作编码字串。
3简介
标准的Base64并不适合直接放在URL⾥传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,⽽这些“%”号在存⼊数据库时还需要再进⾏转换,因为ANSI SQL中已将“%”号⽤作 。
为解决此问题,可采⽤⼀种⽤于URL的改进Base64编码,它在末尾填充'='号,并将标准Base64中的“+”和“/”分别改成
了“-”和“_”,这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统⼀了数据库、表单等处对象 的格式。
另有⼀种⽤于 的改进Base64变种,它将“+”和“/”改成了“!”和“-”,因为“+”,“*”以及前⾯在IRCu中⽤到的“[”和“]”在正则表达式中都可能具有特殊含义。
此外还有⼀些变种,它们将“+/”改为“_-”或“._”(⽤作编程语⾔中的标识符名称)或“.-”(⽤于XML中的Nmtoken)甚
⾄“_:”(⽤于XML中的Name)。
Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位⾼位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要⽐原来的长1/3。
规则
关于这个编码的规则:
②每76个字符加⼀个换⾏符。
③.最后的结束符也要处理。
例⼦(1)
转换前 11111111, 11111111, 11111111 (⼆进制)
转换后 00111111, 00111111, 00111111, 00111111 (⼆进制)
上⾯的三个字节是原⽂,下⾯的四个字节是转换后的Base64编码,其前两位均为0。
转换后,我们⽤⼀个码表来得到我们想要的字符串(也就是最终的Base64编码),这个表是这样的:(摘⾃RFC2045)
转换表
Table 1: The Base64 Alphabet
索引对应字符索引对应字符索引对应字符索引对应字符0A17R34i51z
1B18S35j520
2C19T36k531
3D20U37l542
4E21V38m553
5F22W39n564
6G23X40o575
7H24Y41p586
8I25Z42q597
9J26a43r608
10K27b44s619
11L28c45t62+
12M29d46u63/
13N30e47v 
14O31f48w 
15P32g49x 
16Q33h50y 
例⼦(2)
转换前 10101101,10111010,01110110
转换后 00101011, 00011011 ,00101001 ,00110110
⼗进制 43 27 41 54
对应码表中的值 r b p 2
所以上⾯的24位编码,编码后的Base64值为 rbp2
解码同理,把 rbq2 的⼆进制位连接上再重组得到三个8位值,得出原码。
(解码只是编码的逆过程,有关MIME的RFC还有很多,如果需要详细情况请⾃⾏查。)
第⼀个字节,根据源字节的第⼀个字节处理。
规则:源第⼀字节右移两位,去掉低2位,⾼2位补零。
既:00 + ⾼6位
第⼆个字节,根据源字节的第⼀个字节和第⼆个字节联合处理。
规则如下,第⼀个字节⾼6位去掉然后左移四位,第⼆个字节右移四位
即:源第⼀字节低2位 + 源第2字节⾼4位
第三个字节,根据源字节的第⼆个字节和第三个字节联合处理,
规则第⼆个字节去掉⾼4位并左移两位(得⾼6位),第三个字节右移6位并去掉⾼6位(得低2位),相加即可
//⽤更接近于编程的思维来说,编码的过程是这样的:
//第⼀个字符通过右移2位获得第⼀个⽬标字符的Base64表位置,根据这个数值取到表上相应的字符,就是第⼀//个⽬标字符。
//然后将第⼀个字符与0x03(00000011)进⾏与(&)操作并左移4位,接着第⼆个字符右移4位与前者相或(|),即获得第⼆个⽬标字符。
//再将第⼆个字符与0x0f(00001111)进⾏与(&)操作并左移2位,接着第三个字符右移6位与前者相或(|),获得第三个⽬标字符。
//最后将第三个字符与0x3f(00111111)进⾏与(&)操作即获得第四个⽬标字符。
//在以上的每⼀个步骤之后,再把结果与 0x3F 进⾏ AND ,就可以得到编码后的字符了。
可是等等……聪明的你可能会问到,原⽂的字节数量应该是3的倍数啊,如果这个条件不能满⾜的话,那该怎么办呢?
我们的解决办法是这样的:原⽂剩余的字节根据编码规则继续单独转(1变2,2变3;不够的位数⽤0补全),再⽤=号补满4个字节。这就是为什么有些Base64编码会以⼀个或两个等号结束的原因,但等号最多只有两个。因为:
⼀个原字节⾄少会变成两个⽬标字节
所以余数任何情况下都只可能是0,1,2这三个数中的⼀个。如果余数是0的话,就表⽰原⽂字节数正好是3的倍数(最理想的情况)。如果是1的话,转成2个Base64编码字符,为了让Base64编码是4的倍数,就要补2个等号;同理,如果是2的话,就要补1个等号。
4代码实现
BASH版
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45base64Table=(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 + /);
function str2binary() {
idx=0;
for((i=0; i<${#str}; i++)); do
dividend=$(printf"%d""'${str:i:1}");
for((j=0;j<8;j++)); do
let idx=8*i+7-j;
let bin[$idx]=$dividend%2;
dividend=$dividend/2;
done;
done;
let idx=${#str}*8;
for((i=0; i<appendEqualCnt*2; i++)); do
let bin[$idx]=0;
let idx++;
done;
}
function calcBase64() {
for((i=0; i<${#bin[*]}/6; i++)); do
sum=0;
for((j=0; j<6; j++)); do
let idx=i*6+j;
let n=6-1-j;
let sum=sum+${bin[$idx]}*2**n;
done;
echo-n ${base64Table[$sum]};
done
}
declare-a bin
function base64Encode() {
read-p "please enter ASCII string:"str;
let appendZero=${#str}*8%6;
let bits=${#str}*8;
appendEqualCnt=0;
if[[ $appendZero -ne0 ]]; then
let appendEqualCnt=(6-$appendZero)/2;
fi
str2binary;
calcBase64;
if[[ $appendEqualCnt -eq  2 ]]; then
echo-n "==";
elif[[ $appendEqualCnt -eq  1 ]]; then
echo-n "=";
47 48 49
echo; }
Java版
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 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 52 53 54 55 56 57//模板类模板类写好了再按思路写个实现就可以了
publicinterfaceBase64{
/**
*根据传进来的字符的字节码,查询base64码表的索引,并返回所查到的索引*
*@paramb⼀个编码后的字节码
*@return返回base64码表的索引
*/
publicabstractbytebaseIndex(byteb);
/**
*解码的⽅法
*传进来的是编码后的base64字符的字节码
*解析时是4个⼀组进⾏解析
*@paramb编码后的字符的字节码数组
*@return返回原来的字符串
*/
publicabstractStringbackEncode(byte[]b);
/**
*解码
*将4个字节码中的第1个的后6位(00xxxxxx)和第2个
*字节的前4位的后2位(00yy0000)
*还原为原来的字节码(xxxxxxyy)
*
*@paramfirst4个字节码中的第1个
*@paramsecond4个字节码中的第2个
*@return原来的字符的字节码
*/publicabstractbytebackFirst(bytefirst,bytesecond);
/**
*解码
*将4个字节码中的第2个的后4位(0000xxxx)和第3个
*字节的前6位的后4位(00yyyy00)
*还原为原来的字节码(xxxxyyyy)
*@paramsecond4个字节码中的第2个
*@paramthird4个字节码中的第3个
*@return原来的字符的字节码
*/
publicabstractbytebackSecond(bytesecond,bytethird);
/**
*解码
*将4个字节码中的第3个的后2位(000000xx)和第4个
*字节的后6位(00yyyyyy)
*还原为原来的字节码(xxyyyyyy)
*@paramthird传进来的第3个字符
*@paramfourth传进来的第4个字符
*@return原来的字符的字节码
*/publicabstractbytebackThird(bytethird,bytefourth);
/**
*解码
*将编码后的字符串数组的最后2个字节码还原为原来的字节码
*假如数组末尾剩下2个字节:
*将倒数第2个字节的前后6位(00xxxxxx)
*和倒数第⼀个字节的后2位(000000yy)
*还原为原来的编码(xxxxxxyy)
*假如数组末尾剩下3个字节:
*将倒数第2个字节的前后4位(0000xxxx)
*和倒数第⼀个字节的后4位(0000yyyy)
*还原为原来的编码(xxxxyyyy)
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122*@paramnext_b倒数第1个字节
*@parammove_l倒数第2个字节移动位数的参数
*@parammove_b倒数第1个字节移动位数的参数
*@return原来的字符的字节码
*/
publicbytebackLastOne(bytelast_b,bytenext_b,intmove_l,intmove_b); /**
*编码
*将传进来的字符编码为base64,返回⼀个base64的字符串
*编码时3个字节⼀组进⾏编码,传进来的是要进⾏编码的字符串数组*@paramb要进⾏编码的字符串数组
*@return编码后的字符串
*/
publicabstractStringencode(byte[]b);
/**
*假如字符长度%3!=0,使⽤此⽅法编码末尾字符
*假如b=xxxxyyyy
*假如末尾字节个数等于1:
*将这个字节的前6位作为⼀个字节(00xxxxyy)
*将这个字节的后6位作为⼀个字节(00xxyyyy)
*假如末尾字节个数等于2:
*将这个字节的后6位作为⼀个字节(00xxyyyy)
*@paramb末尾的字符的字节码
*@parammove末尾的字符的字节码要移动的位数的参数
*@return编码后的字节码
*/
publicabstractbytelastOneByte(byteb,intmove);
/**
*编码
*假如b=xxxxyyyy
*将第1个字节的前6位编码为base64
*将3个字节中的第1个⼦节码转为(00xxxxyy)
*@paramb3个字节中的第1个字节
*@return编码后的字节码
*/
publicabstractbytefirstByte(byteb);
/**
*编码
*假如last_b=xxxxyyyynext_b=kkkkffff
*将3个字节中的第1个字节的最后2位(000000yy)
*和第2个字节的前4位(kkkk0000)编码为(00yykkkk)
*
*@paramlast_b3个字节中的第1个字节
*@paramnext_b3个字节中的第2个字节
*@return编码后的字节码
*/
publicabstractbytesecondByte(bytelast_b,bytenext_b);
/**
*编码
*假如last_b=xxxxyyyynext_b=kkkkffff
*将3个字节中的第2个字节的最后4位(0000yyyy)
*和第4个字节的前2位(kk000000)编码为(00yyyykk)
*
*
*@paramlast_b3个字节中的第2个字节
*@paramnext_b3个字节中的第3个字节
*@return编码后的字节码
*/
publicabstractbytethirdByte(bytelast_b,bytenext_b);
/**
*编码
*假如b=xxxxyyyy
*将3个字节中的第3个字节的最后6位(00xxyyyy)
*转码为(00xxyyyy)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。