BASE64编解码

由于历史原因,Email只被允许传送ASCII字符,即一个8位字节的低7位。这里的历史原因就在于第一封Email是由老美发出,当然字符编码也就只考虑美标ASCII码了。到后来,世界各地的人们都想使用便捷的“伊妹儿”,如果你发送了一封带有非 ASCII字符(即字节的最高位是1)的Email通过有历史问题的网关时就可能会出现问题。网关可能会把最高位置为0,这对于使用2字节或更多字节对文字进行编码的国家而言将不能实现正确的信息交流。为了能够使非美标ASCII编码的国家正常的传送Email,单单靠改变字母的位置的恺撒之类的方案也就不行了。这时,BASE64编码方案应运而生。

按照RFC2045的定义,Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)BASE64的主要思想是将输入的字符串或数据编码成只含有{ A - Z , a - z , 0 - 9 , + , / }这64个可打印字符的串,故称为“BASE64”。当然这种加密方式只能达到一眼望去看不出内容的效果,防君子不防小人。

BASE64是当今MIME邮件中常用的编码方式之一,除此之外,BASE64也是HTTP鉴权认证(Authentication)的编码方式之一,即Basic Access Authenticatio(另外一种是Digest Access Authentication)。具体的如果一个URL设置了访问权限(Authorization required for the requested URL),则客户端访问这个URL时,服务器将会发送HTTP/1.0 401 Unauthorized的响应头,客户端浏览器收到该响应后即弹出“连接到*.*.*.*”的登录密码框(User agents must take special care in parsing the WWW-Authenticate field:例如WWW-Authenticate: Basic realm="GeneralUser/Administrator")。其中realm(域)的值将出现在登录对话框中。用户输入的账户按照”用户名字符串:密码字符串”进行BASE64编码后才传送给服务器,服务器进行BASE64解码得到用户输入的用户名密码进行鉴权。

BASE64要求把每3个8 bit的字节转换为四个6 bit的字节(3*8 = 4*6 = 24),然后把6 bit高两位添0,组成4个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。

BASE64编码的方法是将输入数据流每次取6 bit,用此6 bit的值(2^6=64,取值[0,63])作为索引去查表,输出相应的字符。这样,每3个字节将编码为4个可视字符(3×8 →4×6);不满4个字符的以‘=’填充。

原文的字节数量应该是3的倍数,当这个条件不能满足时,用全零字节补足,转化时BASE64编码用=号代替,这就是为什么有些BASE64编码以一个或两个等号结束的原因。具体的做法是:除3余1时,补两个“==”;除3余2时,补一个“=”。

转换后,用一个映射码表来查找相应的BASE64码,映射表如下:(摘自RFC2045)


索引


对应字符


索引


对应字符


索引


对应字符


索引


对应字符


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


15


P


32


g


49


x


16


Q


33


h


50


y

BASE64编码的规则

  ①.把3个字符变成4个字符

  ②每76个字符加一个换行符

  ③.最后的结束符也要处理

案例一:

转换前 10101101 10111010 01110110

转换后 00101011 00011011 00101001 00110110

十进制 43 27 41 54

对应码表中的值 r b p 2

所以上面的24位编码,编码后的Base64值为 rbp2

案例二:

转换前 logansoft:123456

转换前

0x6c 0x6f 0x67 0x61 0x6e 0x73 0x6f 0x66 0x74 0x3a 0x31 0x32 0x33 0x34 0x35 0x36

01101100 01101111 01100111 01100001 01101110 01110011 01101111 01100110 01110100 00111010 00110001 00110010 00110011 00110100 00110101 00110110

转换后

00011011 00000110 00111101 00100111 00011000 00010110 00111001 00110011 00011011 00110110 00011001 00110100 00001110 00100011 00000100 00110010 00001100 00110011 00010000 00110101 00001101 0010(0000)

十进制

27 6 61 39 24 22 57 51 27 54 25 52 14 35 4 50 12 51 16 53 13 32

总共16个字节,16/3=1,故末尾补“==”。查表得“logansoft:123456”的BASE64编码为“bG9nYW5zb2Z0OjEyMzQ1Ng==”,共24个BASE64编码。

解码是编码的逆过程,这里不再详述。

注意:Base64编码为“bG9nYW5zb2Z0OjEyMzQ1NgA=”、“bG9nYW5zb2Z0OjEyMzQ1NgB=” 、“bG9nYW5zb2Z0OjEyMzQ1NgC=” 、“bG9nYW5zb2Z0OjEyMzQ1NgD=”的源码也为“logansoft:123456”。

他们对应的4x6 BASE64索引数据为:

00011011 00000110 00111101 00100111 00011000 00010110 00111001 00110011 00011011 00110110 00011001 00110100 00001110 00100011 00000100 00110010 00001100 00110011 00010000 00110101 00001101 0010(0000)00000000(00000001, 00000010, 00000011)

第21个BASE64索引00001101与第22个BASE64索引0010(0000)进行“尾6中2”的组合还原出字符6(ASCII码为00110110)。接下来解码算法将进行“尾4中4” 的组合还原,第22个BASE64索引0010(0000)的尾四位为“0000”,若第23个BASE64索引的中四位(带下划线的蓝色部分)也为“0000”,则组合出字符NUL(ASCII码为00000000),刚好为C语言字符串的结尾标识符,因此不影响解码结果。

    总结编解码规则如下:

(1)编码(3x8à4x6):头6、尾2头4、尾4头2、尾6。

(2)解码(4x6à3x8):尾6中2、尾4中4、尾2尾6。

在下载软件中加密下载地址的原理

  先以“迅雷下载”为例: 很多下载类网站都提供“迅雷下载”的链接,其地址通常是加密的迅雷专用下载地址。

  如thunder://QUFodHRwOi8vd3d3LmJhaWR1LmNvbS9pbWcvc3NsbTFfbG9nby5naWZaWg==

  其实迅雷的“专用地址”也是用Base64加密的,其加密过程如下:

  一、在地址的前后分别添加AA和ZZ

  如www.baidu.com/img/sslm1_logo.gif变成

  AAwww.baidu.com/img/sslm1_logo.gifZZ

  二、对新的字符串进行Base64编码

  如AAwww.baidu.com/img/sslm1_logo.gifZZ用Base64编码得到

  QUFodHRwOi8vd3d3LmJhaWR1LmNvbS9pbWcvc3NsbTFfbG9nby5naWZaWg==

  三、在上面得到的字符串前加上“thunder://”就成了

  thunder://QUFodHRwOi8vd3d3LmJhaWR1LmNvbS9pbWcvc3NsbTFfbG9nby5naWZaWg==

  另:

Flashget的与迅雷类似,只不过在第一步时加的“料”不同罢了,Flashget在地址前后加的“料”是[FLASHGET]。而QQ旋风的干脆不加料,直接就对地址进行Base64编码了。

附:BASE64编解码C语言实现

[cpp] view plaincopyprint?

  1. // BASE64.H
  2. #ifndef _BASE64_H
  3. #define _BASE64_H
  4. // #include <stdlib.h>
  5. // 编码映射
  6. static const char Base64EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  7. char* Base64Encode(char const* orig);
  8. // 解码映射
  9. static char Base64DecodeTable[256];
  10. static void initBase64DecodeTable();
  11. char* Base64Decode(char const* base64code);
  12. #endif
  13. // BASE64.CPP
  14. //////////////////////////////////////////////////////////////////////////
  15. #include <string.h>
  16. #include <stdio.h>
  17. #include "base64.h"
  18. // "654321:123456" -- "NjU0MzIxOjEyMzQ1Ng=="
  19. // "logansoft:123456" -- "bG9nYW5zb2Z0OjEyMzQ1Ng=="
  20. // "ABC" -- "QUJD"
  21. // "AB"  -- "QUI="
  22. // "A"   -- "QQ=="
  23. // (1)未做76个字符的换行处理
  24. // (2)未做汉字的特殊处理
  25. // BASE64编码
  26. char* Base64Encode(char const* orig)
  27. {
  28. size_t origLen = strlen(orig);
  29. // (1)按比特计算,求算最终结果含多少为BASE64码
  30. int quotientBit = origLen * 8 / 6;  // BASE64码的个数
  31. int remainderBit = origLen * 8 % 6; // 3x8转化为x6的余位
  32. if (remainderBit) // 有余数
  33. {
  34. quotientBit++; // 不足字节的低位补零
  35. }
  36. // (2)按字节计算,求算等号补位数
  37. int quotientByte = origLen / 3; // 3x8转化为x6的分组数
  38. int remainderByte = origLen %3; // 不足一组
  39. if (remainderByte) // 有余数
  40. {
  41. quotientByte++; // 补充一组
  42. }
  43. int cover  = 0; // 等号补充字节数
  44. if (remainderByte == 1)
  45. {
  46. cover = 2; // 补“==”
  47. }
  48. else if (remainderByte == 2)
  49. {
  50. cover = 1; // 补‘=’
  51. }
  52. // (3)3x8 -> 4x6
  53. char* base64code = new char[quotientBit + cover + 1]; // 分配内存
  54. memset(base64code, 0, sizeof(base64code)); // 清零
  55. int i, j;
  56. for (i = 0; i < quotientByte; i++)
  57. {
  58. for (j = 0; j < 4; j++)
  59. {
  60. // 处理最后多出的位(不足位)
  61. if (remainderBit && (4 * i + j + 1 == quotientBit)) // 不为
  62. {
  63. base64code[4 * i + j] = (orig[origLen -1] << (6 - remainderBit)) & 0x3f;
  64. break; // BASE64码转换完毕
  65. }
  66. if (j == 0) // 头6
  67. {
  68. base64code[4 * i + j] = (orig[i * 3] >> 2) & 0x3f;
  69. }
  70. else if (j == 1) // 尾2头4
  71. {
  72. base64code[4 * i + j] = ((orig[i * 3] & 0x03) << 4) |
  73. ((orig[i * 3 + 1] & 0xf0) >> 4);
  74. }
  75. else if (j == 2) // 尾4头2
  76. {
  77. base64code[4 * i + j] = ((orig[i * 3 + 1] & 0x0f) << 2) |
  78. ((orig[i * 3 + 2] & 0xc0) >> 6);
  79. }
  80. else if (j == 3) // 尾6
  81. {
  82. base64code[4 * i + j] = orig[i * 3 + 2]  & 0x3f;
  83. }
  84. }
  85. if (4 * i + j >= quotientBit)
  86. {
  87. break;  // 3x8->4x6转换完毕
  88. }
  89. }
  90. // (4)查表得出BASE64码
  91. int k, index;
  92. for (k = 0; k < quotientBit; k++)
  93. {
  94. index = base64code[k];
  95. base64code[k] = Base64EncodeTable[index];
  96. }
  97. // (5)用等号补足的倍数个BASE64码
  98. if (cover == 1)
  99. {
  100. base64code[quotientBit] = ‘=‘;
  101. }
  102. else if (cover == 2)
  103. {
  104. base64code[quotientBit] = ‘=‘;
  105. base64code[quotientBit + 1] = ‘=‘;
  106. }
  107. base64code[quotientBit + cover] = 0; // 结尾符号
  108. return base64code;
  109. }
  110. // 解码映射
  111. static void initBase64DecodeTable()
  112. {
  113. int i;
  114. for (i = 0; i < 256; ++i)
  115. Base64DecodeTable[i] = (char)0x00;
  116. // default value: invalid
  117. for (i = ‘A‘; i <= ‘Z‘; ++i)
  118. Base64DecodeTable[i] = 0 + (i - ‘A‘);
  119. for (i = ‘a‘; i <= ‘z‘; ++i)
  120. Base64DecodeTable[i] = 26 + (i - ‘a‘);
  121. for (i = ‘0‘; i <= ‘9‘; ++i)
  122. Base64DecodeTable[i] = 52 + (i - ‘0‘);
  123. Base64DecodeTable[(unsigned char)‘+‘] = 62;
  124. Base64DecodeTable[(unsigned char)‘/‘] = 63;
  125. }
  126. // BASE64解码
  127. char* Base64Decode(char const* base64code)
  128. {
  129. initBase64DecodeTable();
  130. size_t base64Len = strlen(base64code);
  131. // (1)等号补位数
  132. int cover = 0;
  133. if (base64code[base64Len - 2] == ‘=‘) // 倒数第二个
  134. {
  135. cover = 2;
  136. }
  137. else if (base64code[base64Len - 1] == ‘=‘) // 倒数第一个
  138. {
  139. cover = 1;
  140. }
  141. // (2)计算源码字节数
  142. int origLen = base64Len * 6 / 8  - cover; // 源码字节数
  143. int quotientByte = origLen / 3; // 3x8分组数
  144. int remainderByte = origLen % 3; // 不足一组
  145. if (remainderByte)
  146. {
  147. quotientByte++; // 多加一组
  148. }
  149. // (3)4x6 -> 3x8
  150. char *orig = new char[origLen + 1];
  151. memset(orig, 0, sizeof(orig));
  152. int i, j;
  153. for (i = 0; i < quotientByte; i++)
  154. {
  155. for (j = 0; j < 3; j++)
  156. {
  157. if (remainderByte && 3 * i + j == origLen)
  158. {
  159. break; // 解码完毕
  160. }
  161. if (j == 0) // 尾6中2
  162. {
  163. orig[3 * i + j] = (Base64DecodeTable[base64code[4 * i]] << 2) |
  164. ((Base64DecodeTable[base64code[4 * i + 1]] & 0x30) >> 4); //
  165. }
  166. else if (j == 1) // 尾4中4
  167. {
  168. orig[3 * i + j] = (Base64DecodeTable[base64code[4 * i + 1]] << 4) |
  169. ((Base64DecodeTable[base64code[4 * i + 2]] & 0x3c) >> 2); //
  170. }
  171. else if (j == 2) // 尾2尾6
  172. {
  173. orig[3 * i + j] = (Base64DecodeTable[base64code[4 * i + 2]] << 6) |
  174. (Base64DecodeTable[base64code[4 * i + 3]] & 0x3f); //
  175. }
  176. }
  177. if (3 * i + j == origLen)
  178. {
  179. break;
  180. }
  181. }
  182. orig[origLen] = 0;
  183. return orig;
  184. }

参考:

BASE64

BASE64编码规则

MIME之Base64编解码

Base64 Encoder/Decoder in C#

Base64加密/解密

Base64编码加密

时间: 2025-01-07 10:23:08

BASE64编解码的相关文章

openssl命令行Base64编解码

openssl对base64编解码的规范支持较差,用它编解码的结果别的语言如php处理很不方便,注意的几点整理如下 1,如果php加密结果做base64编码长度小于64,则需要添加一个换行符openssl才能解码: 2,php需要对base64编码结果每隔64个字符插入一个换行符,openssl才能解码.(原因是openssl默认bufsize缓冲区大小16k,但是一旦涉及base64的计算缓冲区只有80字节,一旦编码结果超过80字节则会计算失败,base64编解码无法更改缓冲区大小) 示例代码

ios Base64编解码工具类及使用

为了避免明码传递http内容,可以用base64编码后传输,收到方再解码,也方便了2进制数据的字符串式传输. 对于ios来说,google给提供了一个很好的工具类,方便进行base64编解码,当然也可以用openssl来进行,但这东西相对来 说比较麻烦.google给提供了3个文件就够了. 官网地址是: http://code.google.com/p/google-toolbox-for-mac/ 这里面有很多宝贝,如果自己找很难找到这3个文件,所以我加到附件里.解压后放到ios工程中即可使用

Java实现BASE64编解码

Java实现BASE64编解码 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs BASE64和其它类似的编码算法通经常使用于转换二进制数据为文本数据,其目的是为了简化存储或传输.更详细地说,BASE64算法主要用于转换二进制数据为ASCII字符串格式.Java语言提供了一个很好的BASE64算法的实现,即Apache Commons Codec工具包.本文将简要地讲述如何使用BASE64以及它是如何工作的. 以下我们用BASE64对字符串进行编码:

Delphi 自带的 Base64 编解码函数

今天帮别人解决一个关于 Base64 编解码的问题,竟然发现 Delphi 自带了 Base64 编解码的单元,叫 EncdDecd,这名字很拗口而且不直观,估计这是一直很少人关注和知道的原因. 这个单元提供两套四个公开函数: 对流的编解码:procedure EncodeStream(Input, Output: TStream); // 编码procedure DecodeStream(Input, Output: TStream); // 解码 // 对字符串的编解码:function E

Base64编解码Android和ios的例子,补充JNI中的例子

1.在Android中java层提供了工具类:android.util.Base64; 里面都是静态方法,方便直接使用: 使用方法如下: Java代码   // Base64 编码: byte [] encode = Base64.encode("Hello, World".getBytes(), Base64.DEFAULT); String enc = new String(encode); Log.d("","base 64 encode = &qu

Java8 BASE64 编解码

Java一直缺少BASE64编码 API,以至于通常在项目开发中会选用第三方的API实现.但是,Java 8实现了BASE64编解码API,它包含到java.util包.下面我会对Java 8的BASE64 API做一个介绍. java.util.Base64工具类提供了一套静态方法获取下面三种BASE64编解码器: 1)Basic编码 2)URL编码 3)MIME编码 Basic编码是标准的BASE64编码,用于处理常规的需求:输出的内容不添加换行符,而且输出的内容由字母加数字组成.下面是用法

iOS开发网络篇之Base64编解码

郝萌主倾心贡献,尊重作者的劳动成果,请勿转载. 如果文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额随意,重在心意^_^ 我要捐赠: 点击捐赠 Cocos2d-X源码下载:点我传送 游戏官方下载:http://dwz.cn/RwTjl 游戏视频预览:http://dwz.cn/RzHHd 游戏开发博客:http://dwz.cn/RzJzI 游戏源码传送:http://dwz.cn/Nret1 在iPhone开发中很多时候都需要将数据进行Base64编解码. 在一些大项目中,就需要将通过R

Java 8实现BASE64编解码

Java一直缺少BASE64编码 API,以至于通常在项目开发中会选用第三方的API实现.但是,Java 8实现了BASE64编解码API,它包含到java.util包.下面我会对Java 8的BASE64 API做一个介绍. java.util.Base64工具类提供了一套静态方法获取下面三种BASE64编解码器: 1)Basic编码2)URL编码3)MIME编码 Basic编码是标准的BASE64编码,用于处理常规的需求:输出的内容不添加换行符,而且输出的内容由字母加数字组成.下面是用法:

python3的base64编解码

使用python3的base64编解码实现字符串的简易加密解密 引言: 在一些项目中,接口的报文是通过base64加密传输的,所以在进行接口自动化时,需要对所传的参数进行base64编码,对拿到的响应报文进行解码: Base64编码是一种"防君子不防小人"的编码方式.广泛应用于MIME协议,作为电子邮件的传输编码,生成的编码可逆,后一两位可能有"=",生成的编码都是ascii字符.优点:速度快,ascii字符,肉眼不可理解缺点:编码比较长,非常容易被破解,仅适用于加