libghttp中也有base加密代码,这里主要是权限认证部分使用到了,base64的代码有很多的介绍,核心思想就是3个字节用4个字节来表示,因此这里不过多介绍理论部分了,在代码中笔者做了很详细的注释,估计看代码注释就能看懂了,唯一不舒服的地方可能是字节的各种逻辑运算处理起来比较绕,但是这个不算难。


b64_alphabet提供了一个换表,只要使用base64加密,那么计算机中的一切字符转换后都是通过这65个字符来表述,转换后的一切数据都是通过查这个表来获得一个字符进行表述的:

const char b64_alphabet[65] = { 
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/=" };

源码就一个加密接口,在这个库中没有解密代码,对加密代码的算法注释说明的非常的清晰,直接看代码应该不难:

/*
* 输入参数:text,待加密的字符串
* 返回值: base加密后的字符串
*/
char *
http_base64_encode(const char *text)
{
char *buffer = NULL;
char *point = NULL;
int inlen = 0;
int outlen = 0;

/* check our args */
if (text == NULL)
return NULL;

/* 使用buffer存储输出数据,首先计算大小 */
inlen = strlen( text );

if (inlen == 0)
{
//传入字符串长度为0则直接返回
buffer = malloc(sizeof(char));
buffer[0] = '\0';
return buffer;
}
outlen = (inlen*4)/3;
if( (inlen % 3) > 0 ) /*outlen避免传入字符串长度不是3的倍数的时候outlen会缺少一部分,这里增加上 */
outlen += 4 - (inlen % 3);

buffer = malloc( outlen + 1 );
memset(buffer, 0, outlen + 1);

/* 循环中每次处理3个字节,剩余的在循环外面处理,这是base的核心思想就是将 将3个字节转换成4个字节,算法是3*8=4*6,
也就是将三个字节转换为24位之后,取6个位组成一个新的字节,6bit高两位补零。
*/
for( point=buffer; inlen>=3; inlen-=3, text+=3 )
{
/*
B=第一个字节
I=第二个字节
T=第三个字节
三个字节的位顺序就是:
B1B2B3B4 B5B6B7B8 | I1I2I3I4 I5I6I7I8 | T1T2T3T4 T5T6T7T8

获取转换后的第一个字节:
进行移位取出第一个字节的高6bit
B1B2B3B4 B5B6 | 00 | 0000 0000 | 0000 0000
*text>>2 = B1B2B3B4 B5B6
则取出来前6位,高2位补零后,转换后第一个字节的索引值是a= 00B1B2 B3B4B5B6
那么:
*(point++) = b64_alphabet[a];*/

*(point++) = b64_alphabet[ *text>>2 ];
/*
获取转换后的第二个字节:
1)将第一个字节的高4位先移除掉,并且与0011 0000进行按位与,这个目的就是将第一个字节的后面两个bit取出来,
这样第一个字节的所有位都处理完了
*text<<4 = B5B6B7B8 0000
(*text<<4 & 0x30) = (B5B6B7B8 0000) & (0011 0000)

2)现在6bit只获取了两个bit,剩下的4bit则从第二个字节获得,因此此时需要对text指针进行移位即(text+1),
已经有两个bit了只需要在第二个字节里面取出高4bit即可,因此进行了*(text+1)>>4操作
*(text+1) = I1I2I3I4 I5I6I7I8
*(text+1)>>4 = 0000 I1I2I3I4

3)后面再将第一个字节获得的2bit和第二个字节获取到的4bit组成到一块就可以了,也就是按位或,那么此时就是
(*text<<4 & 0x30) | *(text+1)>>4 = B5B6 I1I2I3I4
,转换后第二个字节的索引值是a= 00B5B6 I1I2I3I4
*(point++) = b64_alphabet[a];
*/
*(point++) = b64_alphabet[ (*text<<4 & 0x30) | *(text+1)>>4 ];
/*
获取转换后的第三个字节:
1)将第二个字节的高2位先移除掉,并且与0011 1100进行按位与,这个目的就是将第二个字节的后面四个bit取出来,
这样第二个字节的所有位都处理完了
*(text+1) = I1I2I3I4 I5I6I7I8
*(text+1)<<2 = I3I4 I5I6 I7I8 00
*(text+1)<<2 & 0x3c = (I3I4 I5I6 I7I8 00) & (0011 1100) = 00I5I6 I7I800
2)现在取出来第三个字节的高两位
*(text+2) = T1T2T3T4 T5T6T7T8
*(text+2)>>6 = 0000 00T1T2
*(text+1)<<2 & 0x3c) | *(text+2)>>6 = (00I5I6 I7I800) | (0000 00T1T2) = I5I6 I7I8 T1T2
那么转换后第三个字节的索引值是a= 00I5I6 I7I8 T1T2
*(point++) = b64_alphabet[a];
*/
*(point++) = b64_alphabet[ (*(text+1)<<2 & 0x3c) | *(text+2)>>6 ];
/*
获取转换后的第四个字节:
1)此时转换前的第三个字节只剩下六位
*(text+2) = T1T2T3T4 T5T6T7T8
*(text+2) & 0x3f = (T1T2T3T4 T5T6T7T8) & (0011 1111) = 00T3T4 T5T6T7T8
那么转换后第四个字节的索引值是a= 00T3T4 T5T6T7T8
*(point++) = b64_alphabet[a];
*/
*(point++) = b64_alphabet[ *(text+2) & 0x3f ];
}

/*text字符串并长度不一定是3的倍数,因此上述循环处理之后可能剩下一个或者2个字节,还要继续处理*/
if( inlen )
{
/* We always have one trailing byte */
//获取转换后的第二个字节:首先取出来高6位组成一个索引字节
*(point++) = b64_alphabet[ *text>>2 ];
/*
获取转换后的第二个字节:
1)将剩余的第一个字节的剩余2bit取出来
第一个字节的完整8bit数据:xxxx xxxx
先屏蔽高4位
*text<<4 = xxxx 0000
然后再去出来最后2bit
(*text<<4 & 0x30) = (xxxx 0000) & (0011 0000)
2)如果循环处理后剩余了一个字节,那么转换后的第二个字节索引就是1)中剩余的后两个bit
即转换后的索引值就是a = 0000 00xx
3)如果循环处理后剩余了2个字节
第二个字节完整的8bit是:yyyy yyyy
那么在1)的基础上现在需要取出来第二个字节的高4bit
*(text+1) = yyyy yyyy
(text+1)>>4 = 0000 yyyy
即转换后的索引值就是a = 00xx yyyy
*/
*(point++) = b64_alphabet[ (*text<<4 & 0x30) | (inlen==2?*(text+1)>>4:0) ];
/*
获取转换后的第三个字节:
1)如果循环处理后剩余了一个字节,那么转换后的第三个字节就是'='
2)如果循环处理后剩余了2个字节
那么此时提取第二个字节的低4bit
*(text+1) = yyyy yyyy
*(text+1)<<2 = yy yyyy 00
*(text+1)<<2 & 0x3c = (yy yyyy 00) & (0011 1100) = 00yy yy00
*/
*(point++) = (inlen==1?'=':b64_alphabet[ *(text+1)<<2 & 0x3c ] );
/*
获取转换后的第四个字节:
此时转换后的第四个字节就是'='
*/
*(point++) = '=';
}
*point = '\0';
return buffer;
}


​​