本文内容转自网络,如需详细内容,请参考相关网址。

http://my.oschina.net/goal/blog/201032

代码参考:http://blog.csdn.net/prsniper/article/details/7097643

Base64,它用作把任意序列的8位字节描述为一种不易被人直接识别的形式,常用作开发中用于传递参数、浏览器的img标签通过base64字符串来渲染图片以及电子邮件的正文编码等等。

在计算机中显示的字符,比如英文字母、数字以及英文标点符号就是用一个字节来存储,通常称为ASCII码。而简体中文、繁体中文、日文以及韩文等都是用多字节来存储的,通常称之为多字节字符。因为Base编码的输入是字符串的编码,不同编码的字符串的Base64结果是不同的。所以,先来介绍基本的字符编码知识。

字符编码基本知识

最开始的计算机,只支持ASCII码,不支持中文等其他字符,一个字符采用一个字节(8位)表示,只使用低7位,最高位固定为0,因此总共有128个ASCII码(取值范围:0~127)。

为了支持更多地区的语言,各大组织机构和IT厂商开始推广自己的编码方案,以弥补ASCII编码的不足,如GB2312编码、GBK编码和Big5编码,这些编码只是针对局部地区的文字,往下兼容ASCII码,没办法表达所有的语言,这些不同的编码之间没有任何联系,他们之间的转换需要通过查表来实现。

为了提高计算机的信息处理和交换能力,使得各国文字都能在计算机中处理。国际ISO组织制定了通用多字节编码字符集(ISO 10646),简称UCS,这一标准为世界各种主要语言的字符以及附加符号,编制统一的内码。Unicode是Unicode学术学会机构制定的编码系统,从内容上来看,和UCS是同步一致的。

ANSI不代表具体的编码,而是代指本地编码,比如在简体中文版的Windows上面,它代表GB2312编码,在繁体中文版上面,它代表Big5编码,在日文操作系统上面,代表JIS编码。所以,当用户新建并且保存文件类型为ANSI编码,那么那会根据本地系统的编码来确定具体的编码。

Unicode编码

Unicode编码表和字符表是一一映射的,比如汉字”回“,其Unicode编码为56DE,通过56DE就能在Unicode表中找到汉字”回“。Unicode本身定义了每个字符的数值,是字符和自然数的映射关系,而UTF-8、UTF-16则定义了如何在字节流中断字。现在最为常用的Unicode编码为UTF-8和UTF-16.下图为常用的UTF-8的编码形式。在线汉字编码查询点此进入。

从图中可以看出,UTF-8为变长的编码方式(1~6个字节),向下兼容ASCII编码,通常将UTF-8看做单字节或三字节的实现,其他情况非常罕见。每个字节的开始很有规律,方便处理。

UTF-16

UTF-16编码是最直接的Unicode的实现方式,它采用固定两个字节来存储,因为是多字节,所以有小端存储和大端存储两种方式。UTF-16编码是Windows上默认的Unocode编码方式,两个字节小端存储。

在Windows的文本文档中,当另存为时,在编码类型中,有如下几个选择。

就同样一个汉字”回“字,其不同的编码内容如下:

unicode编码结果上面,前面的两个字节FF FE是文件头,代表这是一个UTF16编码的文件,DE 56是”回“字的UTF16编码十六进制表示,低位字节为DE,高位字节为56,组合在一起,就是0x56DE。

有了上述的知识积累,就可以很方便的在UTF8和UTF16之间相互转换了,还是以”回“字为例子,UTF16编码值为  0x56DE,它在0x0000_0800~0x0000_FFFF之间,对于的UTF8字节为三字节。所以,这个转换就是将2字节的UTF16转换为3字节的UTF8编码。注意到UTF-8表中的转换图中的x部分,就是对应0x56DE的各个位的数值。转化结果如下:

UTF8转换为UTF16就是上面的逆过程,知道了转换规则,很容易实现其代码。

中国大陆使用的中文标准为GB2312,一共收录了7445个常用简体汉字和中文符号。

Big5是台湾使用的编码标准,大约编码了8千多个繁体汉字。

HKSCS是香港地区使用的编码标准,但和Big5有所不同。

上述这几套中文编码互不兼容,妨碍软件开发,国际上针对此情况,制定了针对中文的统一字符集GBK和GB18030,其中,GBK已经在Windows、Linux等多种操作系统上实现。GBK1.0收录了21886个符号,分为汉字区和图形符号区,2000年的GB18030是取代GBK1.0,成为正式国家标准,该标准收录了27484个汉字,还收录了藏文、蒙文、维吾尔文等主要少数民族汉字。一般设备上,只需要支持GB2312就足够了。

从ASCII、GB2312、GBK到GB18030,这些编码是向下兼容的,其中,区分中文编码的方法是高字节的最高位不为0.

Unicode只与ASCII兼容,与GB系列码不兼容。例如,“汉”字的Unicode码为6C49,GB码为BABA。

上面讲述了最基本的ASCII、UTF-8、UTF-16等编码的基础知识和对于的转化规则,下面开始介绍本文重点内容Base64编码。

Base64编码

Base64用在必须用可打印字符表示二进制内容的场合,将任意字节转为可读字符的编码,这种编码,不是为安全,因为它是可逆的,而是为了显示。比如需要在xml文档中包含一段音频或者数字签名,URL传递参数,电子邮件的传输编码,可打印字符包括大小写字母(A-Z,a-z),数字(0-9),加号(“+”),正斜杠(“/”),外加补全符号(“=”)

Base64编码要求把3个8位字节(3*8=24位)编码成4个6位的字节(4*6=24位),之后在每个6位字节前面,补充两个0,形成4个8位字节的形式(取值范围在0~63),由于2^6次方等于64,所以每6个位组成一个单元,对于某个可打印的字符,当原始数据不是3的整数倍时,

当最后剩下一个输入字节时,在编码后面添加两个”=”

当最后剩下两个输入字节时,在编码后面添加一个“=”

当数据可以被3整除,就不需要添加数据。

下图为Base64转码表:

上述为标准的Base64编码,标准的Base64编码不适合直接放在URL里面传输,因为URL编码器会将”/“和”+”字符转变为形如”%XX”的形式,而这些”%”号在存入数据库时,还需要转换,因为ANSI SQL中”%“是通配符。

人们为了解决此问题,提出了用于URL的改进Base64编码,它不在末尾填充”=”,并且将标准Base64中的”+”和”/”分别改成了”-”和“_”,这样就免去URL的编解码和数据存储时的格式转换,长度保持不变,统一了数据库、表单等处理对象的格式。

编码过程,简单下来可以总结为:

1. 先将输入的字节数凑成3的整数倍N,然后申请N*4/3+1这么多的空间内存空间

2. 按照3个字节为一组,转换为4个字节的输出原则转换,特别要注意申请空间的最后一位的处理

3. 解密时,有取值判断和查表两种方法,推荐使用查表法。

4. 在字符串输出的最后,需要加上结束标志符’\0’

下面给出C语言的Base64代码,在网友给出的代码基础上,经过自己认真测试,现在贡献出来,希望能够帮助到其他人。我在这里面,对结束符的处理是映射为0xFF,个人觉的,只要知道这个标志出现了,做适当的处理就可以了。

/**************************************************************************************************Filename:       base64.cRevised:        2014-12-09 15.18Description: this file use to descript the Base64 encode and decodeAuthor:          huhaoEmail:           huhao0126@163.com
***************************************************************************************************/#include "stdlib.h"
#include "base64.h"static const char BASE_CODE[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";static const unsigned char base64_dec_map[128] =
{127, 127, 127, 127, 127, 127, 127, 127, 127, 127,   //0 ~ 9127, 127, 127, 127, 127, 127, 127, 127, 127, 127,   //10~19127, 127, 127, 127, 127, 127, 127, 127, 127, 127,   //20~29127, 127, 127, 127, 127, 127, 127, 127, 127, 127,   //30~39127, 127, 127,  62, 127, 127, 127,  63,  52,  53,   //40~4954,  55,  56,  57,  58,  59,  60,  61, 127, 127,    //50~59127, 0xFF, 0, 0, 0,   0,   1,   2,   3,   4,        //60~695,   6,   7,   8,   9,  10,  11,  12,  13,  14,     //70~7915,  16,  17,  18,  19,  20,  21,  22,  23,  24,    //80~8925, 127, 127, 127, 127, 127, 127,  26,  27,  28,    //90~9929,  30,  31,  32,  33,  34,  35,  36,  37,  38,    //100~10939,  40,  41,  42,  43,  44,  45,  46,  47,  48,    //110~11949,  50,  51, 127, 127, 127, 127, 127               //120~127
};/*************************************************************************************************** @fn          base64_encode** @brief       This function encode the bindata into base64 format.** input parameters** @param       bindata   - the input bindata* @param       output    - the output base64 data.* @param       slen      - the  length of input data.** output parameters** None.** @return the length of encoder output***************************************************************************************************/
int Base64Encode(const unsigned char* bindata, unsigned char* output,int slen)
{int vlen = 0;unsigned char* temp_data;temp_data = bindata;while(slen > 0 ){*output++ = BASE_CODE[  (temp_data[0]>>2) & 0x3F ];if(slen > 2 ) //长度大于三个字符 处理生成4个字符
        {*output++ = BASE_CODE[  ( ( temp_data[0] & 0x03 )<<4) | ( temp_data[1] >>4) ];*output++ = BASE_CODE[  ( ( temp_data[1] & 0x0F )<<2) | ( temp_data[2] >>6) ];*output++ = BASE_CODE[    ( temp_data[2] & 0x3F )];}else if( slen  == 2)  //恰好为两个字符
        {*output++ = BASE_CODE[  ( ( temp_data[0] & 0x03 )<<4) | ( temp_data[1] >>4) ];*output++ = BASE_CODE[  ( ( temp_data[1] & 0x0F )<<2)];*output++ = '=';}else if( slen == 1)   //恰好为一个字符
        {*output++ = BASE_CODE[ (temp_data[0]&0x03) << 4];*output++ = '=';*output++ = '=';}temp_data += 3;slen    -= 3;vlen    += 4;}*output = '\0';     //this is very improtantreturn vlen;
}/*************************************************************************************************** @fn          GetCharIndex** @brief       This function get the mapping value.** input parameters** @param       c       - Base64 code** output parameters*              none*  it has two ways to map from ciphertext to plaintext,one is lookup-table,and the other is value judgements.* @return  original value
***************************************************************************************************/
unsigned char GetCharIndex(unsigned char c)
{#if 1if(  ( c >= 'A' )  && ( c <= 'Z')){return c - 'A';}else if( (c >= 'a') && (c <= 'z' )){return c-'a'+26;}else if( (c >= '0') && ( c <= '9')){return c - '0' + 52;}else if( c == '+'){return 62;}else if( c == '/'){return 63;}else if(c == '='){return 0xFF;}#elsereturn base64_dec_map[c];#endifreturn 0;
}/*************************************************************************************************** @fn          BaseDecode** @brief       This function decode the bindata into base64 format.** input parameters** @param       input    - the encoded input data* @param       output   - the decode  output data* @param       sLen     - the length of encoded input data.** output parameters*              none** @return      vlen     - the length of decode data***************************************************************************************************/
int Base64Decode(const unsigned char* input,unsigned char *output,int sLen)
{static unsigned char lpCode[4] = {0};unsigned char* data_temp = input;int vlen = 0;//Base64 length must be a multiple of 4 including '='if( sLen % 4 ){return -1;}while(sLen > 0 ){lpCode[0] = GetCharIndex(data_temp[0]);lpCode[1] = GetCharIndex(data_temp[1]);lpCode[2] = GetCharIndex(data_temp[2]);lpCode[3] = GetCharIndex(data_temp[3]);if(  lpCode[3] == 0xFF ){if( lpCode[2] == 0xFF )   // if there has two '=' at the end
            {*output++ = (lpCode[0] << 2) | (lpCode[1] >>4);vlen +=1;break;}else                   // if there has one '=' at the end
            {*output++ = (lpCode[0] << 2) | (lpCode[1] >>4);*output++ = (lpCode[1] << 4) | (lpCode[2] >>2);vlen +=2;break;}}else{*output++ = (lpCode[0] << 2) | (lpCode[1] >>4);*output++ = (lpCode[1] << 4) | (lpCode[2] >>2);*output++ = (lpCode[2] << 6) | (lpCode[3]);data_temp+=4;sLen -=4;vlen +=3;}}*output = '\0'; //this is very improtantreturn vlen;
}/*
main test function
*/
int test_base64()
{unsigned char* output_buffer = NULL;char input_str[100]={0};int allocate_len;int input_len;int output_len;printf("Please input string : \n ");scanf("%s",input_str);input_len = strlen(input_str);printf("the length of input is %d \n",strlen(input_str));//补齐字节数,使得输出缓存为4的倍数,这样来考虑,先把输入长度补齐到3的倍数,然后将其乘以4再除以3allocate_len =  ( input_len % 3 ) ? (  input_len + 3 - input_len%3 ) :( input_len);allocate_len =  ( allocate_len * 4 )/3;output_buffer = (unsigned char*)malloc(allocate_len+1);     //加1 很重要,用于结束编解码的输出字符串if(NULL == output_buffer){printf("allocate memory fail! \n");return -1;}else{printf("success allocate %d bytes. \n",allocate_len);memset(output_buffer,0,allocate_len);}output_len = Base64Encode(input_str,output_buffer,input_len);printf("Base64ENcode(\" %s \" ,encoding output length is %d \")  \n encode content is %s \" \n\n",input_str,output_len,output_buffer);memset(input_str,0,sizeof(input_str));output_len = Base64Decode(output_buffer,input_str,output_len);printf("Base64Decode(\" %s  \" ,decoding output length is %d \")  \n decode content is %s   \n",output_buffer,output_len,input_str);free(output_buffer);        //release the allocated memoryoutput_buffer = NULL;
}

执行结果如下:

完成这篇博客,从基础知识的准备到base64原理的了解,再到最终代码的实现和调试,花费了一天的时间,具体原理不难,调试过程中,遇到了很多问题,深知,网上得来终觉浅,绝知此事要躬行。别人给出的代码,自己如果不敲一片,字字斟酌,如果只是匆匆扫过,是怎么样也不会体会别人的思路和方法。现在网络资源异常丰富,我们在别人的基础上,进行自己的改进和优化,博采众长,提升自己。

对代码来说,光说不练假把式,虽说是今天实现的只是一个小小的功能,把小功能步步都想清楚,各种情况都处理好,每天深入了解学习一个知识点,能够解决一个问题,那这一天就很有价值,没有白白度过。

转载于:https://www.cnblogs.com/cherishui/p/4153396.html

Base64编码原理与应用相关推荐

  1. base64编码_几分钟看懂Base64编码原理

    Base64简介 Base64是基于64个可打印字符(小写字母a-z,大写字母A-Z,数字0-9,符号"+","/" 再加上作为垫字的"=" ...

  2. Base64 编码原理及代码实现

    Base64 编码原理及代码实现 所谓 base64 编码就是从 ASCII 码表中选取64个可打印字符(A-Za-z0-9+/)作为基本字符集对其它字符进行编码转换.加上作为填充的 "=& ...

  3. 密码学-编码算法:Base64编码原理和使用

    1.Base64简介 Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法.Base64编码是从二进制到字符的过程,可用于在 ...

  4. 5分钟学会Base64编码原理

    Base64编码原理 一.前言        相信很多开发的小伙伴当听到 Base64的时候,都会误认为是它一种加密解密的算法.        其不然,Base64其实是一种编码格式,其作用:解决乱码 ...

  5. Base64编码原理与实现

    Base64编码的原理是按bit将每6个bit转换成Base64编码表中的相应字符.下面是Base64的编码表: 0 A 17 R 34 i 51 z 1 B 18 S 35 j 52 0 2 C 1 ...

  6. 一文轻松明白 Base64 编码原理

    把图片丢进浏览器,打开sources能看到一长串字符串,这是图片的Base64编码.这一长串编码到底是怎么生成的呢? 我们接下来探索一下base64编码的原理 Base64 名称的由来 Base64编 ...

  7. C++安全方向(二):2.3 base64编码原理讲解

    我们目前的编码可以理解为base256 4位是0-16 6位是0-63,能表示我们的base64,所以base64我们是取6位表示一个字节.

  8. base64编码原理+源码

    看一下Base64的索引表,字符选用了"A-Z.a-z.0-9.+./" 64个可打印字符.数值代表字符的索引,这个是标准Base64协议规定的,不能更改.64个字符用6个bit位 ...

  9. Base64编码的原理与常用实现

    这篇主要是为了后面好介绍加密算法,做的铺垫. 这个是基础,什么是一个程序员的涵养,这些基础就是涵养. 平时可能用不到,但必须得会. 如果连这个原理都说不上来,就别玩王者荣耀绝地求生英雄联盟和平精英了, ...

最新文章

  1. 3Blue1Brown深度学习笔记 深度学习之神经网络的结构 Part 1 ver 2.0
  2. placeholder 颜色更改
  3. 论:CMMI项目集成管理(IPM)
  4. vue.js 动态添加组件
  5. python排序的方法_python中排序的一种方法
  6. Effective C++学习第十一天
  7. for 循环 和 Array 数组对象
  8. [ JAVA编程 ] double类型计算精度丢失问题及解决方法
  9. gtk_widget_modify_bg的用法
  10. SCOM2012SP1环境准备和安装
  11. mysql备份psb文件怎么打开,当迁移 Navicat 到新电脑时,如何保留数据库连接信息?...
  12. python各个关键词的意思_想学好Python,你必须了解Python中的35个关键词
  13. CMakeFiles/species.inc.dir/build.make:57: recipe for target 'CMakeFiles/species.inc' failed
  14. 征集大家的网站如何防范DDOS攻击解决方案
  15. 深入针式PKM应用系列
  16. 【测试人生】安卓FPS测试详解
  17. 庄辰超的势能,梁建章的心力
  18. 正斜杠(左斜杠)和反斜杠(右斜杠)
  19. Zotero如何更改字体大小
  20. 零电压开关(ZVS)电路原理与设计(整理)

热门文章

  1. gva explaination
  2. In English or Chinese?
  3. directly to phd is good for laying a solid foundation for future career
  4. 来自长辈的5句教导!
  5. <<温泉屋的小老板娘>>观后感
  6. 静态函数造成GC的原因
  7. 每日阅读(产品) 汤道QQ与微信
  8. JVM技术周报第2期
  9. Python 字典 fromkeys()方法
  10. ECSHOP 模版文件里的编辑区域