关于Base64
编码(
转载)
feijunjun(军仔) 2002-05-02 15:16:52发表.
把一三个字符的24位码转换成四个高两位为0的ASCII码,其实也就是四个字母[取自于码表: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/]
如 10101101 10111010 01110110
----------------- --------
这里是一个中文字[8位高一位不为0] 这是一个英文字母[高一位为0]
可以转成
00101011 00011011 00101001 00110110
------ ------ ------ ------ =>这里正好是上面的 那27位值
2B 1B 2A 36
以下是 10 进制码表中的索引
43 27 42 54
对应码表中的值
r b q 2
所以上面的24位编码,编码后值为 rbq2
解码同理把rbq2的二进制位连接上再重组得到三个 8位值,得出原码
很明白了吧,呵呵
====================================================================
soundbug(兼职乞丐) 2002-03-22 09:42:53发表
我收藏的一篇文章:
-------------------------------------------------------------------
一般大多数包含"="的不是"Base64"编码格式,只有"quoted-printable"编码格式才会经
常出现"="虽然都是MIME编码,但是算法不一样
,"quoted-printable"的我不太清楚.讲一下Base64的吧.
Base64算法是把3个8位字符(24)转换成4个6位字符(32),因此编码后的长度会扩大1/3,
进行编码转换时需要用到一张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
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
在VB中可以简单的将其保存为一个常量:
Private Const Base64Table =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
编码过程是这样的,第一个字符通过右移2位获得第一个目标字符的Base64表位置,根据
这个数值取到表上相应的字符,就是第一个目标字符
,然后将第一个字符左移6位加上第二个字符右移4位,即获得第二个目标字符,再将第二
个字符左移4位加上第三个字符右移6位,获得第三个
目标字符,最后取第三个字符的右6位即获得第四个目标字符.
例如我们取一个简单的字符串"TEST..."
将其用SourceByte = StrConv(SourceText, vbFromUnicode)转换后获得二进制数组:
T E S T ...
84 69 83 84 ...
01010100 01000101 01010011 01010100 ...
01010100/01000101/01010011/01010100
01010100010001010101001101010100
转换后:
01010100010001010101001101010100
010101/000100/010101/010011/010101/00
010101 000100 010101 010011 010101 00....
21 4 21 19 21 ...
V E V T V ...
最后得到的就是"VEVTV..."
对于第一个目标字符我们可以这样做:
(SourceByte(1) and 252)/4
第二个:
(SourceByte(1) and 3)*64 + (SourceByte(2) and 240)/16
第三个:
(SourceByte(2) and 15)*16 + (SourceByte(3) and 48)/64
第四个:
(SourceByte(3) and 63)
Base64解码过程正好相反,我就不多说了,另外有关MIME的RFC还是有很多的,如果需要详
细情况请自己查找,我上面那张表就摘自
<RFC1521#
MIME (Multipurpose Internet Mail Extensions)
Part One: Mechanisms for Specifying and Describing the Format of Internet
Message Bodies>
====================================================================
xuying() 2002-08-21 12:10:55发表
MIME/BASE64 的算法很简单,它将字符流顺序放入一个 24 位的缓冲区,缺字符的地方补零。然后将缓冲区截断成为 4 个部分,高位在先,每个部分 6 位,用下面的 64 个字符重新表示:“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop qrstuvwxyz0123456789+/”。如果输入只有一个或两个字节,那么输出将用等号“=”补足。这可以隔断附加的信息造成编码的混乱。这就是BASE64。
UEsDBBQAAgAIAEapPiS/mrkHoQEAAEECAAAMAAAAYWNhZDd+dWUudHh0dVFRb5swGHyPlP9Q5Iet
TUICzCUJASTiFuIQhwbHRJnUqmRsndqmVQO0CsK/fXbRVvVh+AV9vrvv7txunYiPV8rAW3n33w5B
R9FAN3ld34Axr9OHIjtkt7wC3bmKHD+zznjteTGvjBnVFGCdxz265XW7dfI+ZVFyRjegO3hix8nl
fGcdjeLqy/rGTp0Sj+Jp8Djho9oIWRSX0IYIwwmWbF4RHKYK0ByCaI9u4u3HukYZIvE32+fZyz7L
BASE64编码转换原理
Base64编码其实是将3个8位字节转换为4个6位字节,( 3*8 = 4*6 = 24 ) 这4个六位字节
其实仍然是8位,只不过高两位被设置为0. 当一个字节只有6位有效时,它的取值空间为0
到 2的6次方减1 即63,也就是说被转换的Base64编码的每一个编码的取值空间为(0~63)
。
事实上,0~63之间的ASCII码有许多不可见字符,所以应该再做一个映射,映射表为
‘A‘ ~ ‘Z‘ ? ASCII(0 ~ 25)
‘a’ ~ ‘z‘ ? ASCII(26 ~ 51)
‘0’ ~ ‘9‘ ? ASCII(52 ~ 61)
‘+‘ ? ASCII(62)
‘/‘ ? ASCII(63)
这样就可以将3个8位字节,转换为4个可见字符。
具体的字节拆分方法为:(图(画得不好,领会精神 :-))
aaaaaabb ccccdddd eeffffff
~~~~~~~~ ~~~~~~~~ ~~~~~~~~
字节 1 字节 2 字节 3
||
//
00aaaaaa 00bbcccc 00ddddee 00ffffff
注:上面的三个字节位原文,下面四个字节为Base64编码,其前两位均为0。
这样拆分的时候,原文的字节数量应该是3的倍数,当这个条件不能满足时,用全零字节
补足,转化时Base64编码用=号代替,这就是为什么有些Base64编码以一个或两个等号结
束的原因,但等号最多有两个,因为:如果F(origin)代表原文的字节数,F(remain)代
表余数,则
F(remain) = F(origin) MOD 3 成立。
所以F(remain)的可能取值为0,1,2.
如果设 n = [F(origin) – F(remain)] / 3
当F(remain) = 0 时,恰好转换为4*n个字节的Base64编码。
当F(remain) = 1 时,由于一个原文字节可以拆分为属于两个Base64编码的字节,为了
让Base64编码是4的倍数,所以应该为补2个等号。
当F(remain) = 2 时,由于两个原文字节可以拆分为属于3个Base64编码的字节,同理,
应该补上一个等号。
====================================================================
duz() 2001-04-14 01:05:00 发表
#include <windows.h>
#define BaseCode64Size(nInputSize) ((nInputSize+2)/3*4)
#define DeBaseCod64Size(nInputSize) ((nInputSize/4)*3)
BOOL DecodeBase64(const char *pszIn, BYTE *pszOut, int *nOutLen);
BOOL EncodeBase64(const BYTE* pszIn, int nInLen, char* pszOut);
int CodeFromChar(char x);
const char m_base64tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz0123456789+/";
int CodeFromChar(char x)
{
if('A'<=x&&x<='Z')
return x-'A';
if('a'<=x&&x<='z')
return x-'a'+26;
if('0'<=x&&x<='9')
return x-'0'+52;
if(x=='+')
return 62;
if(x=='/')
return 63;
if(x=='='||x=='/r'||x=='/n')
return 64;
return -1;
}
int sizeofstr(const char *str)
{
int i=0;
while(str[i++]);
return i-1;
}
BOOL DecodeBase64(const char *pszIn, BYTE *pszOut, int *nOutLen)
{
if(IsBadStringPtr(pszIn,0xFFFFFFFF))
return FALSE;
int len=sizeofstr(pszIn);
int OutSize=DeBaseCod64Size(len);
if(IsBadWritePtr(pszOut,OutSize))
return FALSE;
int nInPos=0;
int nOutPos=0;
for(int i=0;pszIn[nInPos]!='/0';i++)
{
int c1,c2,c3,c4;
if((c1=CodeFromChar(pszIn[nInPos++]))==-1)
return FALSE;
if(c1==64)
continue;
if((c2=CodeFromChar(pszIn[nInPos++]))==-1)
return FALSE;
if(c2==64)
return FALSE;
if((c3=CodeFromChar(pszIn[nInPos++]))==-1)
return FALSE;
if(c3==64)
return FALSE;
if((c4=CodeFromChar(pszIn[nInPos++]))==-1)
return FALSE;
if(c4==64)
return FALSE;
if(c1==-1||c2==-1||c3==-1||c4==-1)
{
return FALSE;
}
if(c1==64||c2==64||c3==64||c4==64)
{
nInPos-=3;
return FALSE;
}
pszOut[nOutPos++]=(BYTE)((c1<<2)|(c2>>4));
pszOut[nOutPos++]=(BYTE)((c2<<4)|(c3>>2));
pszOut[nOutPos++]=(BYTE)((c3<<6)|(c4));
}
*nOutLen=nOutPos;
return TRUE;
}
BOOL EncodeBase64(const BYTE* pszIn, int nInLen, char* pszOut)
{
int nOutLen;
if(IsBadReadPtr(pszIn,nInLen))
return FALSE;
nOutLen=BaseCode64Size(nInLen)+1;
if(IsBadWritePtr(pszOut,nOutLen))
return FALSE;
int nInPos=0;
int nOutPos=0;
for (int i=0; i<nInLen/3; ++i)
{
//Get the next 2 characters
int c1 = (int)pszIn[nInPos++];
int c2 = (int)pszIn[nInPos++];
int c3 = (int)pszIn[nInPos++];
//Encode into the 4 6 bit characters
pszOut[nOutPos++] = m_base64tab[(c1 & 0xFC) >> 2];
pszOut[nOutPos++] = m_base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
pszOut[nOutPos++] = m_base64tab[((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6)];
pszOut[nOutPos++] = m_base64tab[c3 & 0x3F];
}
switch (nInLen % 3)
{
case 0:
{
pszOut[nOutPos++]='/0';
break;
}
case 1:
{
int c1 = pszIn[nInPos];
pszOut[nOutPos++] = m_base64tab[(c1 & 0xFC) >> 2];
pszOut[nOutPos++] = m_base64tab[((c1 & 0x03) << 4)];
pszOut[nOutPos++] = '=';
pszOut[nOutPos++] = '=';
pszOut[nOutPos++] = '/0';
break;
}
case 2:
{
int c1 = pszIn[nInPos++] ;
int c2 = pszIn[nInPos] ;
pszOut[nOutPos++] = m_base64tab[(c1 & 0xFC) >> 2];
pszOut[nOutPos++] = m_base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
pszOut[nOutPos++] = m_base64tab[((c2 & 0x0F) << 2)];
pszOut[nOutPos++] = '=';
pszOut[nOutPos++] = '/0';
break;
}
default:
{
//This is impossible, so release memory is not needed
return FALSE;
}
}
return TRUE;
}