Base64算法的简介与C语言实现

2008-04-28 14:25

1. Base64算法的简介
1) 简述

该算法被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式,达到一眼望去完全看不出内容。此算法的复杂程度要小,效率高。如果是基于以上两点,那么我们使用最简单的单字母代替法等即可,实际上Base64要稍微复杂些,这是因为在Email的传送过程中,由于历史原因,Email只被允许传送ASCII字符,即一个8位字节的低7位。
2) 具体描述
把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在每个6位的前面补两个0,形成8位,即一个字节。再根据每个字节的值,用下表中的值替换,不足4个字节的,补“=”。例如,高山(0xB8DFC9BD),先将(0xB8DFC9)分割成四个字节(0x2E0D3F09),用下表值替换为(uN/J);再将(0xBD)分割成(0x2F10)用下表值替换为(vQ),再补两个(=),合起来就形成了编码后的课件字符串(uN/J vQ==)。

2. Base64算法的实现
1) 编码函数

char gEncBase64(unsigned char* indata, unsigned long inlen,\
        unsigned char *outdata, unsigned long *outlen);//编码
功能:对长度为inlen的输入数据indata进行base64编码,编码后的数据存放在提前开辟好的内存outdata中去,其长度outlen不得小于((inlen+2)/3)*4。
参数:
  indata:要进行编码的数据的地址指针。
  Inlen:要进行编码的数据的长度。
  Outdata:编码后数据存放的地址指针。
  Outlen:传入outdata的长度,传出编码后的数据的长度。
返回值:成功时,返回编码后的数据的地址,失败时,返回NULL。
2) 解码函数
char gDecBase64(unsigned char* indata, unsigned long inlen,\
        unsigned char *outdata, unsigned long *outlen);//解码
功能:对长度为inlen的输入数据indata进行base64解码,解码后的数据存放在提前开辟好的内存outdata中去,其长度outlen不得小于inlen*3/4。
参数:
  indata:要进行解码的数据的地址指针。
  Inlen:要进行解码的数据的长度。
  Outdata:解码后数据存放的地址指针。
  Outlen:传入outdata的长度,传出解码后的数据的长度。
返回值:成功时,返回解码后的数据的地址,失败时,返回NULL。


3. 源代码
1) 头文件

#ifndef _gjs_BASE64_H
#define _gjs_BASE64_H
char* gEncBase64(char* data,unsigned long inlen,unsigned long *outlen);//编码
char* gDecBase64(char* data,unsigned long inlen,unsigned long *outlen);//解码
#endif
2) 源文件
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "ctype.h"
const char gBase[]={"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="};
static union
{//为了方便操作
    struct
    {
        unsigned long d:6;
        unsigned long c:6;
        unsigned long b:6;
        unsigned long a:6;
    } s;
    unsigned char c[3];
} u;
char *gEncBase64(char* data,unsigned long inlen,unsigned long *outlen)
{//编码
    char *p=NULL,*ret=NULL,*p1=NULL;  
    int tlen=0,i=0,j=0;
    if(data==NULL || inlen==0)
        return NULL;//传入参数不对
    tlen=inlen/3;
    if(inlen%3!=0)
        tlen=tlen+1;
    tlen=tlen*4;
    *outlen=tlen;//编码后的数据长度
    if((ret=(char*)malloc(tlen+1))==NULL)
        return NULL;//内存开辟失败
    memset(ret,0,tlen+1);
    p=data;p1=ret;tlen=inlen;
    while(tlen>0)
    {//循环编码
        u.c[0]=u.c[1]=u.c[2]=0;
        for(i=0;i<3;i++)
        {//取3字节
            if(tlen<=0) break;
            u.c[2-i]=(char)*p;
            tlen--;p++;
        }
        if(i==0)
            break;//没取到
        switch(i)
        {//根据取到的字节数分情况
            case 1://取到1字节
                *p1=gBase[u.s.a];p1++;
                *p1=gBase[u.s.b];p1++;
                *p1=gBase[64];p1++;//'=';
                *p1=gBase[64];p1++;//'=';
                break;
            case 2://取到2字节
                *p1=gBase[u.s.a];p1++;
                *p1=gBase[u.s.b];p1++;
                *p1=gBase[u.s.c];p1++;
                *p1=gBase[64];p1++;//'=';
                break;
            case 3://取到3字节
                *p1=gBase[u.s.a];p1++;
                *p1=gBase[u.s.b];p1++;
                *p1=gBase[u.s.c];p1++;
                *p1=gBase[u.s.d];p1++;
                break;
            default:
                break;
        }
    }
    return ret;
}
char* gDecBase64(char* data,unsigned long inlen,unsigned long *outlen)
{//解码
    int c1,c2,c3,c4;
    char ch1=0,ch2=0,ch3=0,ch4=0,*p=NULL,*ret=NULL;
    char *p1=NULL,*p2=NULL,*p3=NULL,*p4=NULL;
    int tlen=0,rlen=0;
    if(data==NULL || inlen==0)
        return NULL;//传入参数错误
    tlen=inlen*3/4;
    if((ret=(char*)malloc(tlen+1))==NULL)
        return NULL;//内存开辟失败  
    memset(ret,0,tlen+1);
    p=data;tlen=inlen;rlen=0;
    while(tlen>0)
    {//循环解码
        if(tlen>0)
        {//取第1位
            ch1=*p;p++;tlen--;
            if((p1=(char*)strchr(gBase,ch1))==NULL)//不在表中
            return 0;
        }
        if(tlen>0)
        {//取第2位
            ch2=*p;p++;tlen--;
            if((p2=(char*)strchr(gBase,ch2))==NULL)//不在表中
            return 0;
        }
        if(tlen>0)
        {//取第3位
            ch3=*p;p++;tlen--;
            if((p3=(char*)strchr(gBase,ch3))==NULL)//不在表中
            return 0;
        }
        if(tlen>0)
        {//取第4位
            ch4=*p;p++;tlen--;
            if((p4=(char*)strchr(gBase,ch4))==NULL)//不在表中
            return 0;
        }
        if((ch1==gBase[64])||(ch2==gBase[64])
            ||(ch3==gBase[64] && ch4!=gBase[64]))
            return 0;//编码有错误

        u.s.a=p1-gBase;
        u.s.b=p2-gBase;
        if (ch3==gBase[64])
        {//原数据只有1个字节
                *(ret+rlen)=(char)u.c[2];rlen++;
        }
        else if (ch4==gBase[64])
        {//原数据只有2个字节
                u.s.c=p3-gBase;
                *(ret+rlen)=(char)u.c[2];rlen++;
                *(ret+rlen)=(char)u.c[1];rlen++;
        }
        else
        {//原数据有3个字节
                u.s.c=p3-gBase;
                u.s.d=p4-gBase;
                *(ret+rlen)=(char)u.c[2];rlen++;
                *(ret+rlen)=(char)u.c[1];rlen++;
                *(ret+rlen)=(char)u.c[0];rlen++;
        }
    }
    *outlen=rlen;
    return ret;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值