现在的位置: 首页 > 综合 > 正文

加密算法(二)——BASE64

2013年09月11日 ⁄ 综合 ⁄ 共 4504字 ⁄ 字号 评论关闭

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编码的字节,同理,
应该补上一个等号。

下面我给出Base64的编码和解码的C语言描述:  
  /*Base64编码*/  
  void   Base64(unsigned   char   chasc[3],unsigned   char   chuue[4])  
  /*  
      chasc:未编码的二进制代码  
      chuue:编码过的Base64代码  
  */  
  {  
    int   i,k=2;  
    unsinged   char   t=NULL;  
    for(i=0;i<3;i++)  
    {  
      *(chuue+i)=*(chasc+i)>>k;  
      *(chuue+i)|=t;  
      t=*(chasc+i)<<(8-k);  
      t>>=2;  
      k+=2;  
    }  
    *(chuue+3)=*(chasc+2)&63;  
    for(i=0;i<4;i++)  
          if((*(chuue+i)>=0)&&(*(chuue+i)<=25))   *(chuue+i)+=65;  
          else   if((*(chuue+i)>=26)&&(*(chuue+i)<=51))   *(chuue+i)+=71;  
          else   if((*(chuue+i)>=52)&&(*(chuue+i)<=61))   *(chuue+i)-=4;  
          else   if(*(chuue+i)==62)   *(chuue+i)=43;  
          else   if(*(chuue+i)==63)   *(chuue+i)=47;  
  }  
  /*Base64解码*/  
  void   unBase64(unsigned   char   chuue[4],unsigned   char   chasc[3])  
  /*  
  chuue:未解码的Base64代码  
  chasc:解码过的二进制代码  
  */  
  {int   i,k=2;  
    unsigned   char   t=NULL;  
    for(i=0;i<4;i++)  
            if((*(chuue+i)>=65)&&(*(chuue+i)<=90))   *(chuue+i)-=65;  
            else   if((*(chuue+i)>=97)&&(*(chuue+i)<=122))   *(chuue+i)-=71;  
            else   if((*(chuue+i)>=48)&&(*(chuue+i)<=57))   *(chuue+i)+=4;  
            else   if(*(chuue+i)==43)   *(chuue+i)=62;  
            else   if(*(chuue+i)==47)   *(chuue+i)=63;  
            else   if(*(chuue+i)==61)   *(chuue+i)=0;  
    for(i=0;i<3;i++)  
    {*(chhex+i)=*(chuue+i)<<k;  
      k+=2;  
      t=*(chuue+i+1)>>8-k;  
      *(chhex+i)|=t;  
    }  
  }

 ----------------------------------------------------------------------------------------------------------------

base64编解码原理与函数

原因与原理:
早期邮件中都是明文 这在英语国家 并且没有附件的情况下是合适的 (那里网络还不是很普及 并且网络速度很慢)
但是后面随着internet的发展 人们希望传送除了英语以外的其它东西 如应用程序等 同时其它国家也希望使用自己本国语言来写邮件
因此产生了对在邮件中传送二进制的要求
邮件的传送是以明文方式传送的
如果直接传送二进制 那邮全服务器可能会理解错 如把正文中内容错理解成指令(想想二进行中的/0等特殊字符) 所以发明了base64编码
使用64个可打印字符对内容进行编码
这64个字符是
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
编码原理是: 把3个字节使用上面的字母进行转换 转换成4个字节 每个字节都只有6bit
第一个字节由第一个byte的高6位组成
第二个字节的高位由第一个byte的低二位组成 低4位由第二个byte的高4位组成
第三个字节的高位由第二个byte的低四位组成 低2位由第三个字节的高2位组成
第四个字节是剩下的bit

自己可以直观的在纸上画 把18个bit平分成4份 就这样
下面是编码例子

/ encode base64 string
// return encode len

CODE
/**
* @brief 进行base64编码
*
* @param buf   [out]保存编码结果
* @param text  [in]要编码的串
* @param size  [in]text的长度
*
* @return 编码长度
**/
int Base64Enc(unsigned char *buf,const unsigned char*text,int size)
{
   static char *base64_encoding =
       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
   int buflen = 0;

   while(size>0){
       *buf++ = base64_encoding[ (text[0] >> 2 ) & 0x3f];
       if(size>2){
           *buf++ = base64_encoding[((text[0] & 3) << 4) | (text[1] >> 4)];
           *buf++ = base64_encoding[((text[1] & 0xF) << 2) | (text[2] >> 6)];
           *buf++ = base64_encoding[text[2] & 0x3F];
       }else{
           switch(size){
               case 1:
                   *buf++ = base64_encoding[(text[0] & 3) << 4 ];
                   *buf++ = '=';
                   *buf++ = '=';
                   break;
               case 2:
                   *buf++ = base64_encoding[((text[0] & 3) << 4) | (text[1] >> 4)];
                   *buf++ = base64_encoding[((text[1] & 0x0F) << 2) | (text[2] >> 6)];
                   *buf++ = '=';
                   break;
           }
       }

       text +=3;
       size -=3;
       buflen +=4;
   }

   *buf = 0;
   return buflen;
}

char GetBase64Value(char ch)
{
   if ((ch >= 'A') && (ch <= 'Z'))
       return ch - 'A';
   if ((ch >= 'a') && (ch <= 'z'))
       return ch - 'a' + 26;
   if ((ch >= '0') && (ch <= '9'))
       return ch - '0' + 52;
   switch (ch) {
       case '+':
           return 62;
       case '/':
           return 63;
       case '=': /* base64 padding */
           return 0;
       default:
           return 0;
   }
}

/**
* @brief base64解码
*
* @param buf   [out]解码结果
* @param text  [in]要解码的串,必须是4的倍数
* @param size  [in]text大小
*
* @return -1出错,>=0解码缓冲区使用长度
**/
int Base64Dec(unsigned char *buf,const unsigned char*text,int size)
{
   if(size%4)
       return -1;
   unsigned char chunk[4];
   int parsenum=0;

   while(size>0){
       chunk[0] = GetBase64Value(text[0]);
       chunk[1] = GetBase64Value(text[1]);
       chunk[2] = GetBase64Value(text[2]);
       chunk[3] = GetBase64Value(text[3]);

       *buf++ = (chunk[0] << 2) | (chunk[1] >> 4);
       *buf++ = (chunk[1] << 4) | (chunk[2] >> 2);
       *buf++ = (chunk[2] << 6) | (chunk[3]);

       text+=4;
       size-=4;
       parsenum+=3;
   }

   return parsenum;
}

抱歉!评论已关闭.