Base64的编码和解码

来源:互联网 发布:阳西网络问政 编辑:程序博客网 时间:2024/04/30 21:00

为什么要使用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个字节为单位,依次取6位数据并在前面补上两个0形成新的8位编码,由于3×8=4×6,这样3个字节的输入会变成4个字节的输出,长度上增加了1/3上面的处理还不能保证得到的字符都是可见字符,为了达到此目的,Base64制定了一个编码表,进行统一的转换,见表11.1。码表的大小为26=64,这也是Base64名称的由来。由于编码是以3个字节为单位,当剩下的字符数量不足3个字节时,则应使用0进行填充,相应地,输出字符则使用‘=’占位,因此编码后输出的文本末尾可能会出现12个‘=’

11.1 Base64编码表

编码

编码

编码

编码

编码

编码

编码

编码

0

A

8

I

16

Q

24

Y

32

g

40

o

48

w

56

4

1

B

9

J

17

R

25

Z

33

h

41

p

49

x

57

5

2

C

10

K

18

S

26

a

34

i

42

q

50

y

58

6

3

D

11

L

19

T

27

b

35

j

43

r

51

z

59

7

4

E

12

M

20

U

28

c

36

k

44

s

52

0

60

8

5

F

13

N

21

V

29

d

37

l

45

t

53

1

61

9

6

G

14

O

22

W

30

e

38

m

46

u

54

2

62

+

7

H

15

P

23

X

31

f

39

n

47

v

55

3

63

/


加密举例:

  让我们再来看一个实际的例子,加深印象!

  转换前 10101101 10111010 01110110 

  转换后 00101011 00011011 00101001 00110110 

  十进制 43 27 41 54 

  对应码表中的值 r b p 2 

  所以上面的24位编码,编码后的Base64值为 rbp2 

  编码的过程是这样的: 

  第一个字符通过右移2位获得第一个目标字符的Base64表位置,根据这个数值取到表上相应的字符,就是第一个目标字符。

  然后将第一个字符左移4位或上第二个字符右移4位,即获得第二个目标字符。

  再将第二个字符左移2位或上第三个字符右移6位,获得第三个目标字符。

  最后取第三个字符的右6位即获得第四个目标字符。

  在以上的每一个步骤之后,再把结果与 0x3F 进行 AND 位操作,就可以得到编码后的字符了。 

  若是原文的字节不够的地方可以用全0来补足,转换时Base64编码用=号来代替。这就是为什么有些Base64编码会以一个或两个等号结束的原因,但等号最多只有两个。因为:

  余数 = 原文字节数 MOD 3 

  所以余数任何情况下都只可能是0,1,2这三个数中的一个。如果余数是0的话,就表示原文字节数正好是3的倍数(最理想的情况啦)。如果是1的话,为了让Base64编码是3的倍数,就要补2个等号;同理,如果是2的话,就要补1个等号。

解密举例:

   假设转换后对应base64编码表的字符为:

    对应码表中的值 r b p 2 ,将其转化为bsae64表中的位置,比如r在base64的43号位置,那么转化后为 00101011,则有:

    转换后:         00101011 00011011 00101001 00110110

变为原始数据:10101101 10111010 01110110

编码的过程是这样的:

   先将源字符串转化为bsae64表中对应的位置;

    第一个字符通过左移2位 或上第二个字符右移4位得到第一个目标字符;

    第二个字符通过左移4位 或上第三个字符右移2位得到第二个目标字符;

    第三个字符通过左移6位 或上第四个字符得到第三个目标字符;

   每次四个字符转化为3个目标字节,如果源字符串的长度不等于4的倍数,可以考虑告知用户直接结束程序或者强制转换,剩下不足的则不为0

/*

* base64_encode & decode

*/

#include< stdio.h>

#include< stdlib.h>

#include< string.h>

char base64_map[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

char base64_decode_map[256] = {

255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,

255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,

255, 255, 255,  62, 255, 255, 255,  63,  52,  53,  54,  55,  56,  57,  58, 59,  60,  61, 255, 255,

255, 0, 255, 255, 255,  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, 255, 255, 255, 255, 255, 255,  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, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,

255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,

255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,

255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,

255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,

255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,

255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};

 

unsigned char test[100]= "493712874";

unsigned char test1[100]= "gdfgd";

unsigned char encode[100], decode[100];

void base64_encode(const char *src, int src_len, char *dst)

{

    int i = 0, j = 0;

    for (i; (src_len - i) / 3; i += 3) {

        dst[j++] = base64_map[(src[i] >> 2) & 0x3f];

        dst[j++] = base64_map[((src[i] << 4) | (src[i + 1] >> 4)) & 0x3f];

        dst[j++] = base64_map[((src[i + 1] << 2) | (src[i + 2] >> 6 )) & 0x3f];

        dst[j++] = base64_map[src[i + 2] & 0x3f];

    }

 

/*不足3的倍数*/

    if (src_len % 3 == 1) {

        dst[j++] = base64_map[(src[i] >> 2) & 0x3f];

        dst[j++] = base64_map[(src[i] << 4) & 0x3f];

        dst[j++] = '=';

        dst[j++] = '=';

    }

    else if (src_len % 3 == 2) {

        dst[j++] = base64_map[(src[i] >> 2) & 0x3f];

        dst[j++] = base64_map[((src[i] << 4) | (src[i + 1] >> 4)) & 0x3f];

        dst[j++] = base64_map[(src[i + 1] << 2) & 0x3f];

        dst[j++] = '=';

    }

    dst[j] = '\0';

}

 

//若是不是4的倍数,强制解码?

void base64_decode(const char *src, int src_len, char *dst)

{

    int i = 0, j = 0;

    if(src_len % 4 != 0)

    {

        printf("sound code is not four time\n");

        exit(1);       

    }

 

    for (i; (src_len - i) / 4; i += 4) {

        dst[j++] = base64_decode_map[src[i]] << 2 | \

        base64_decode_map[src[i + 1]] >> 4;

        dst[j++] = base64_decode_map[src[i + 1]] << 4 | \

        base64_decode_map[src[i + 2]] >> 2;

        dst[j++] = base64_decode_map[src[i + 2]] << 6 | \

        base64_decode_map[src[i + 3]];

    }

    dst[j] = '\0';

}

 

int main(void)

{

    printf("%s\n",test);

 

    base64_encode(test, strlen(test), encode);

    printf("%s\n",encode);

 

    printf("%s\n",test1);

    base64_encode(test1, strlen(test1), encode);

    printf("%s\n",encode);

 

    base64_decode(encode, strlen(encode), decode);

    printf("%s\n",decode);

 

    return 0;

}

参考文献:

【1】http://blog.chinaunix.net/u/15780/showart_43620Array.html

【2http://blog.csdn.net/wangjj_016/article/details/2794245

【3】http://baike.baidu.com/view/469071.htm

0 0
原创粉丝点击