zoukankan      html  css  js  c++  java
  • 浅谈Base64编码

    我打赌当你见到Base64这个词的时候你会觉得在哪里见过,因为在你能够上网看到这篇文章的时候你已经在后台使用它了。如果您对二进制数有所了解,你就可以开始读它了。

    打开一封Email,查看其原始信息(您可以通过收取、导出该邮件用文本编辑器查看)。你会看到类似这样的一个效果:

    Date: Thu, 25 Dec 2003 06:33:07 +0800
    From: "eSX?!" <snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net>
    Reply-To: snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net
    To: "snaix" <snaix@126.com'>snaix@126.com>
    Subject:
    X-mailer: Foxmail 5.0 beta2 [cn]
    Mime-Version: 1.0
    Content-Type: text/plain;
    charset="gb2312"
    Content-Transfer-Encoding: base64

    xOO6w6OsU25haVgNCg0KoaGhodXiysfSu7j2QmFzZTY0tcSy4srU08q8/qOhDQoNCkJlc3QgV2lz
    aGVzIQ0KIAkJCQkNCqGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaEgICAgICAgICAgICAgICBl
    U1g/IQ0KoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoSAgICAgICAgICAgICAgIHNuYWl4QHll
    YWgubmV0DQqhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhICAgICAgICAgMjAwMy0x
    Mi0yNQ0K

    是否看到了“base64”标记?是否看到了标记下面的一行乱码?也许你会恍然大悟,对!这就是Base64编码。

    什么是Base64?

    按 照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)

    为什么要使用Base64?

    在设计这个编码的时候,我想设计人员最主要考虑了3个问题:
    1.是否加密?
    2.加密算法复杂程度和效率
    3.如何处理传输?

        加密是肯定的,但是加密的目的不是让用户发送非常安全的Email。这种加密方式主要就是“防君子不防小人”。即达到一眼望去完全看不出内容即可。
    基 于这个目的加密算法的复杂程度和效率也就不能太大和太低。和上一个理由类似,MIME协议等用于发送Email的协议解决的是如何收发Email,而并不 是如何安全的收发Email。因此算法的复杂程度要小,效率要高,否则因为发送Email而大量占用资源,路就有点走歪了。

        但 是,如果是基于以上两点,那么我们使用最简单的恺撒法即可,为什么Base64看起来要比恺撒法复杂呢?这是因为在Email的传送过程中,由于历史原 因,Email只被允许传送ASCII字符,即一个8位字节的低7位。因此,如果您发送了一封带有非ASCII字符(即字节的最高位是1)的Email通 过有“历史问题”的网关时就可能会出现问题。网关可能会把最高位置为0!很明显,问题就这样产生了!因此,为了能够正常的传送Email,这个问题就必须 考虑!所以,单单靠改变字母的位置的恺撒之类的方案也就不行了。关于这一点可以参考RFC2046。
    基于以上的一些主要原因产生了Base64编码。

    算法详解

        Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。
    具体转化形式间下图:
    字符串“张3”
    11010101 11000101 00110011

    00110101 00011100 00010100 00110011
    表1

    可以这么考虑:把8位的字节连成一串110101011100010100110011
    然后每次顺序选6个出来之后再把这6二进制数前面再添加两个0,就成了一个新的字节。之后再选出6个来,再添加0,依此类推,直到24个二进制数全部被选完。
    让我们来看看实际结果:

    字符串“张3”
    11010101 HEX:D5 11000101 HEX:C5 00110011 HEX:33

    00110101 00011100 00010100 00110011
    字符’5’ 字符’^"’ 字符’^T’ 字符’3’
    十进制53 十进制34 十进制20 十进制51
    表2

    这样“张3 ”这个字符串就被Base64表示为”5^"^T3”了么?。错!
    Base64编码方式并不是单纯利用转化完的内容进行编码。像’^"’字符是控制字符,并不能通过计算机显示出来,在某些场合就不能使用了。Base64有其自身的编码表:

    Table 1: The Base64 Alphabet
    Value Encoding Value Encoding Value Encoding Value Encoding
    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 (pad) =
    14 O 31 f 48 w
    15 P 32 g 49 x
    16 Q 33 h 50 y
    表3

    这 也是Base64名称的由来,而Base64编码的结果不是根据算法把编码变为高两位是0而低6为代表数据,而是变为了上表的形式,如”A”就有7位,而 ”a”就只有6位。表中,编码的编号对应的是得出的新字节的十进制值。因此,从表2可以得到对应的Base64编码:

    字符串“张3”
    11010101 HEX:D5 11000101 HEX:C5 00110011 HEX:33

    00110101 00011100 00010100 00110011
    字符’5’ 字符’^"’ 字符’^T’ 字符’3’
    十进制53 十进制34 十进制20 十进制51
    字符’1’ 字符’i’ 字符’U’ 字符’z’
    表4

    这样,字符串“张3”经过编码后就成了字符串“1iUz”了。
    Base64将3个字节转变为4个字节,因此,编码后的代码量(以字节为单位,下同)约比编码前的代码量多了1/3。之所以说是“约”,是因为如果代码量正好是3的整数倍,那么自然是多了1/3。但如果不是呢?
    细心的人可能已经注意到了,在The Base64 Alphabet中的最后一个有一个(pad) =字符。这个字符的目的就是用来处理这个问题的。
    当代码量不是3的整数倍时,代码量/3的余数自然就是2或者1。转换的时候,结果不够6位的用0来补上相应的位置,之后再在6位的前面补两个0。转换完空出的结果就用就用“=”来补位。譬如结果若最后余下的为2个字节的“张”:

    字符串“张”
    11010101 HEX:D5 11000101 HEX:C5

    00110101 00011100 00010100
    十进制53 十进制34 十进制20 pad
    字符’1’ 字符’i’ 字符’U’ 字符’=’
    表6

    这样,最后的2个字节被整理成了“1iU=”。
    同理,若原代码只剩下一个字节,那么将会添加两个“=”。只有这两种情况,所以,Base64的编码最多会在编码结尾有两个“=”
    至于将Base64的解码,只是一个简单的编码的逆过程,读者可以自己探讨。我将在文章的最后给出解码算法。

    算法实现
    其实在算法详解的时候基本上已经说的很清楚了。用于程序上,除去约束判断,大概可以分为如下几步几步:
    读取数据3字节用AND取前6位,放入新的变量中右移两位,高两位清0AND取第一个字节的后2位和第二个字节的前4位移位放入新变量中右移两位,清0……依此类推。
    解码的类C语言实现的算法:
    BYTE LMoveBit(int base, int MoveNum)
    {
    BYTE result=base;
    if(MoveNum==0)return 1;
    if(MoveNum==1)return MoveNum;
    result=base<<(MoveNum-1);
    return result;
    }

    char base64_alphabet[]=
    {'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','+','/','='};
    BYTE Base64Decode(char *base64code, DWORD base64length)
    {
    char buf[4];
    int i,j;
    int k;
    int l=0;
    BYTE temp1[4],temp2;
    BYTE *Buffer=new BYTE[base64length*3/4];
    DWORD base64a=(base64length/4)-1;
    DWORD base64b=0;
    for(;base64b<base64a+1;base64b++)
    {
    for(i=0;i<4;i++)
    {
    buf[i]=*(base64code+(base64b*4)+i);
    for(j=0;j<65;j++)
    {
    if(buf[i]==base64_alphabet[j])
    {
    temp1[i]=j;
    break;
    }
    }
    }
    i--;
    for(k=1;k<4;k++)
    {
    if(temp1[i-(k-1)]==64){m_padnum++; continue;}
    temp1[i-(k-1)]=temp1[i-(k-1)]/LMoveBit(2,(k-1)*2);
    temp2=temp1[i-k];
    temp2=temp2&(LMoveBit(2,k*2)-1);
    temp2*=LMoveBit(2,8-(2*k));//move 4
    temp1[i-(k-1)]=temp1[i-(k-1)]+temp2;
    Buffer[base64b*3+(3-k)]=temp1[i-(k-1)];
    }
    }
    return Buffer;
    }

    根据这段算法,文章最开始给出的Email内容,可以解码为:
    你好,SnaiX

    这是一个Base64的测试邮件!

    Best Wishes!
    eSX?!
    snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net
    2003-12-25

    如文章有问题恳请指出并与我联系:snaix@126.com'>snaix@126.com

    主要参考资料:
    RFC2045
    RFC2046
    《奇妙的Base64编码》,罗聪
    以及一些来自互联网上的其他资料

    DOC文档也可以从
    http://popscanner.icpcn.com/download/base64.doc
  • 相关阅读:
    6-Python爬虫-分布式爬虫/Redis
    ES 查询时 排序报错(fielddata is disabled on text fileds by default ... )解决方法
    Intellij Idea webstorm 激活
    Intellij Idea 配置jdk
    java 获取(格式化)日期格式
    js 跳转 XSS漏洞 预防
    CSS去掉背景颜色
    js对象无法当成参数传递 解决方法
    Elasticsearch java api
    java多条件查询SQL语句拼接的小技巧
  • 原文地址:https://www.cnblogs.com/pony/p/1457583.html
Copyright © 2011-2022 走看看