Base64

base64是一种将二进制的01序列转化成ASCII字符的编码方法。编码后的文本或者二进制消息, 就可以运用SMTP等只支持ASCII字符的协议传送了. Base64 一般被认为会平均增加 33% 的报文长度, 而且经过编码的消息对于人类来说是不可读的。

Base64是一种基于 64 个可打印字符来表示二进制数据的表示方法。由于 2 的 6 次方等于 64, 所以每 6 个比特为一个单元, 对应某个可打印字符。三个字节有 24 个比特, 对应于 4 个 base64 单元, 即 3 个字节需要用 4 个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9, 这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法, 和之后binhex的版本使用不同的64字符集来代表6个二进制数字, 但是它们不叫Base64.

Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据。包括 MIME 的 email, email via MIME, 在XML中存储复杂数据.

linux 命令行 base64 编码/解码, base64 encode/decode

1
2
3
4
5
6
# encode
base64 sample.txt > encodedData.txt
cat encodedData.txt

# decode
echo eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9 |base64 -d

标准 base64, StdEncoding

1
A-Z, a-z, 0-9, /, +, = (pad/填充)

Base64 URL

1
A-Z, a-z, 0-9, _, -

Base64URL 采用了和 Base64 一样的算法作为主要标准,在以下几个方面做了稍许调整:

  • 将 + 替换成了 -
  • 将 / 替换成了 _
  • 不再需要填充字符
  • 禁止行分隔符

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

为解决此问题,可采用一种用于 URL 的改进Base64编码,它不在末尾填充'='号,并将标准 Base64 中的"+"和”/“分别改成了”-“和”_",这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。

https://base64.guru/standards/base64url

正则 base64 变种

1
A-Z, a-z, 0-9, -, !

填充

base64 编码收到一个8位字节序列,将这个二进制序列流划分成6位的块。二进制序列有时不能正好平均地分为6位的块,在这种情况下,就在序列末尾填充零位,使二进制序列的长度成为24的倍数(6和8的最小公倍数)。 对已填充的二进制进行编码时,任何完全填充(不包括原始数组中的位)的6位组都有特殊的第65个符号"="表示。如果6位组是部分填充的,就将填充位设置为0. 下面会写一个填充实例。初始输入字符串为"a:a"为3个字节(24位)。24是6和8的倍数,因此按照上面给出的例子计算。无需填充就会得到base64编码为"YTph”。 然而,再增加一个字符,输入字符串变为"a:aa”,转换为二进制就会有32位长。而6和8的下一个公倍数为48.因此要添加16为的填充码。填充的前4位是与数据位混合在一起的。得到的6位组01xxxx,会被当作010000、十进制中的16,或者base64编码的Q来处理。剩下的两个6位组都是填充码,用=来表示。

a:a – 011000 010011 101001 100001 – YTph

a:aa – 011000 010011 101001 100001 011000 01xxxx xxxxxx xxxxxx – YTphYQ==

a:aaa – 011000 010011 101001 100001 011000 010110 0001xx xxxxxx – YTphYWE=

a:aaaa – 011000 010011 101001 100001 011000 010110 000101 1000001 – YTphYWFh

https://segmentfault.com/a/1190000004533485

Base64是网络上最常见的用于传输 8Bit 字节代码的编码方式之一,大家可以查看 RFC2045~RFC2049,上面有MIME的详细规范。Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符 (一般为128-bit的UUID) 编码为一个字符串,用作HTTP表单和HTTP GET URL 中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL (包括隐藏表单域) 中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。

另有一种用于正则表达式的改进Base64变种,它将"+"和”/“改成了”!“和”-",因为"+”,"*“以及前面在IRCu中用到的”[“和”]“在正则表达式中都可能具有特殊含义。

此外还有一些变种,它们将"+/“改为”-“或”.” (用作编程语言中的标识符名称) 或”.-” (用于XML中的Nmtoken) 甚至”_:” (用于XML中的Name) 。

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

规则

关于这个编码的规则:

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

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

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

这样说会不会太抽象了?不怕,我们来看一个例子:

转换前 aaaaaabb ccccdddd eeffffff

转换后 00aaaaaa 00bbcccc 00ddddee 00ffffff

应该很清楚了吧?上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。

转换后,我们用一个码表来得到我们想要的字符串 (也就是最终的Base64编码) ,这个表是这样的: (摘自RFC2045)

让我们再来看一个实际的例子,加深印象!

转换前 10101101 10111010 01110110

转换后 00101011 00011011 00101001 00110110

十进制 43 27 41 54

对应码表中的值 r b p 2

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

解码同理,把 rbq2 的二进制位连接上再重组得到三个8位值,得出原码。

(解码只是编码的逆过程,在此我就不多说了,另外有关MIME的RFC还是有很多的,如果需要详细情况请自行查找。)

用更接近于编程的思维来说,编码的过程是这样的:

第一个字符通过右移2位获得第一个目标字符的Base64表位置,根据这个数值取到表上相应的字符,就是第一个目标字符。

然后将第一个字符左移4位加上第二个字符右移4位,即获得第二个目标字符。

再将第二个字符左移2位加上第三个字符右移6位,获得第三个目标字符。

最后取第三个字符的右6位即获得第四个目标字符。

在以上的每一个步骤之后,再把结果与 0x3F 进行 AND 位操作,就可以得到编码后的字符了。

可是等等……聪明的你可能会问到,原文的字节数量应该是3的倍数啊,如果这个条件不能满足的话,那该怎么办呢?

我们的解决办法是这样的: 原文的字节不够的地方可以用全0来补足,转换时Base64编码用=号来代替。这就是为什么有些Base64编码会以一个或两个等号结束的原因,但等号最多只有两个。因为:

余数 = 原文字节数 MOD 3

所以余数任何情况下都只可能是0,1,2这三个数中的一个。如果余数是0的话,就表示原文字节数正好是3的倍数 (最理想的情况啦) 。如果是1的话,为了让Base64编码是3的倍数,就要补2个等号;同理,如果是2的话,就要补1个等号。

Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符 (一般为128-bit的UUID) 编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL (包括隐藏表单域) 中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。

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

打开一封Email,查看其原始信息 (您可以通过收取、导出该邮件用文本编辑器查看) 。你会看到类似这样的一个效果: Date: Thu, 25 Dec 2003 06:33:07 +0800

From: “eSX?!” <snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net> Reply-To: snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net To: “snaix” <snaix@126.com'>snaix@126.com> Subject: X-mailer: Foxmail 5.0 beta2 [cn] Mime-Version: 1.0 Content-Type: text/plain; charset="gb2312” Content-Transfer-Encoding: base64xOO6w6OsU25haVgNCg0KoaGhodXiysfSu7j2QmFzZTY0tcSy4srU08q8/qOhDQoNCkJlc3QgV2lz aGVzIQ0KIAkJCQkNCqGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaEgICAgICAgICAgICAgICBl U1g/IQ0KoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoSAgICAgICAgICAgICAgIHNuYWl4QHll YWgubmV0DQqhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhICAgICAgICAgMjAwMy0x Mi0yNQ0K是否看到了"base64"标记?是否看到了标记下面的一行乱码?也许你会恍然大悟,对!这就是Base64编码。什么是Base64?按照RFC2045的定义,Base64被定义为: 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?

在设计这个编码的时候,我想设计人员最主要考虑了3个问题: 1.是否加密? 2.加密算法复杂程度和效率 3.如何处理传输?

加密是肯定的,但是加密的目的不是让用户发送非常安全的Email。这种加密方式主要就是"防君子不防小人”。即达到一眼望去完全看不出内容即可。 基于这个目的加密算法的复杂程度和效率也就不能太大和太低。和上一个理由类似,MIME协议等用于发送Email的协议解决的是如何收发Email,而并不是如何安全的收发Email。因此算法的复杂程度要小,效率要高,否则因为发送Email而大量占用资源,路就有点走歪了。

但是,如果是基于以上两点,那么我们使用最简单的恺撒法即可,为什么Base64看起来要比恺撒法复杂呢?这是因为在Email的传送过程中,由于历史原因,Email只被允许传送ASCII字符,即一个8位字节的低7位。因此,如果您发送了一封带有非ASCII字符 (即字节的最高位是1) 的Email通过有"历史问题"的网关时就可能会出现问题。网关可能会把最高位置为0!很明显,问题就这样产生了!因此,为了能够正常的传送Email,这个问题就必须考虑!所以,单单靠改变字母的位置的恺撒之类的方案也就不行了。关于这一点可以参考RFC2046。 基于以上的一些主要原因产生了Base64编码。

算法详解

Base64编码要求把3个8位字节 (38=24) 转化为4个6位的字节 (46=24) ,之后在6位的前面补两个0,形成8位一个字节的形式。 具体转化形式间下图: 字符串"张3” 11010101 11000101 00110011

00110101 00011100 00010100 00110011 表1

可以这么考虑: 把8位的字节连成一串110101011100010100110011 然后每次顺序选6个出来之后再把这6二进制数前面再添加两个0,就成了一个新的字节。之后再选出6个来,再添加0,依此类推,直到24个二进制数全部被选完。 让我们来看看实际结果:

字符串"张3” 11010101 HEX:D5 11000101 HEX:C5 00110011 HEX:33

00110101 00011100 00010100 00110011 字符'5’ 字符'^’ 字符'^T’ 字符'3’ 十进制53 十进制34 十进制20 十进制51 表2

这样"张3 “这个字符串就被Base64表示为"5^^T3"了么?。错! Base64编码方式并不是单纯利用转化完的内容进行编码。像'^'字符是控制字符,并不能通过计算机显示出来,在某些场合就不能使用了。Base64有其自身的编码表:

Table 1: The Base64 Alphabet Value Encoding Value Encoding Value Encoding Value Encoding 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 (pad) = 14 O 31 f 48 w 15 P 32 g 49 x 16 Q 33 h 50 y 表3

这也是Base64名称的由来,而Base64编码的结果不是根据算法把编码变为高两位是0而低6为代表数据,而是变为了上表的形式,如"A"就有7位,而"a"就只有6位。表中,编码的编号对应的是得出的新字节的十进制值。因此,从表2可以得到对应的Base64编码:

  字符串"张3"

11010101 HEX:D5 11000101 HEX:C5 00110011 HEX:33

  00110101 00011100 00010100 00110011

字符'5’ 字符'^’ 字符'^T’ 字符'3’ 十进制53 十进制34 十进制20 十进制51 字符'1’ 字符’i’ 字符’U’ 字符’z’ 表4

  这样,字符串"张3"经过编码后就成了字符串"1iUz"了。

Base64将3个字节转变为4个字节,因此,编码后的代码量 (以字节为单位,下同) 约比编码前的代码量多了1/3。之所以说是"约”,是因为如果代码量正好是3的整数倍,那么自然是多了1/3。但如果不是呢? 细心的人可能已经注意到了,在The Base64 Alphabet中的最后一个有一个(pad) =字符。这个字符的目的就是用来处理这个问题的。 当代码量不是3的整数倍时,代码量/3的余数自然就是2或者1。转换的时候,结果不够6位的用0来补上相应的位置,之后再在6位的前面补两个0。转换完空出的结果就用就用"="来补位。譬如结果若最后余下的为2个字节的"张”:

  字符串"张"

11010101 HEX:D5 11000101 HEX:C5

  00110101 00011100 00010100

十进制53 十进制34 十进制20 pad 字符'1’ 字符’i’ 字符’U’ 字符'=’ 表6

  这样,最后的2个字节被整理成了"1iU="。

同理,若原代码只剩下一个字节,那么将会添加两个"=”。只有这两种情况,所以,Base64的编码最多会在编码结尾有两个"=” 至于将Base64的解码,只是一个简单的编码的逆过程,读者可以自己探讨。我将在文章的最后给出解码算法。

  算法实现

其实在算法详解的时候基本上已经说的很清楚了。用于程序上,除去约束判断,大概可以分为如下几步几步: 读取数据3字节用AND取前6位,放入新的变量中右移两位,高两位清0AND取第一个字节的后2位和第二个字节的前4位移位放入新变量中右移两位,清0……依此类推。 解码的类C语言实现的算法: BYTE LMoveBit(int base, int MoveNum) { BYTE result=base; if(MoveNum==0)return 1; if(MoveNum==1)return MoveNum; result=base«(MoveNum-1); return result; }

  char base64_alphabet[]=

{‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,‘G’,‘H’,‘I’,‘J’,‘K’,‘L’,‘M’,‘N’,‘O’,‘P’, ‘Q’,‘R’,‘S’,‘T’,‘U’,‘V’,‘W’,‘X’,‘Y’,‘Z’,‘a’,‘b’,‘c’,‘d’,‘e’,‘f’, ‘g’,‘h’,‘i’,‘j’,‘k’,‘l’,‘m’,‘n’,‘o’,‘p’,‘q’,‘r’,‘s’,‘t’,‘u’,‘v’, ‘w’,‘x’,‘y’,‘z’,‘0’,‘1’,‘2’,‘3’,‘4’,‘5’,‘6’,‘7’,‘8’,‘9’,‘+’,'/',‘=’}; BYTE Base64Decode(char base64code, DWORD base64length) { char buf[4]; int i,j; int k; int l=0; BYTE temp1[4],temp2; BYTE _Buffer=new BYTE[base64length_3/4]; DWORD base64a=(base64length/4)-1; DWORD base64b=0; for(;base64b<base64a+1;base64b++) { for(i=0;i<4;i++) { buf[i]=(base64code+(base64b4)+i); for(j=0;j<65;j++) { if(buf[i]==base64_alphabet[j]) { temp1[i]=j; break; } } } i-; for(k=1;k<4;k++) { if(temp1[i-(k-1)]==64){m_padnum++; continue;} temp1[i-(k-1)]=temp1[i-(k-1)]/LMoveBit(2,(k-1)2); temp2=temp1[i-k]; temp2=temp2&(LMoveBit(2,k2)-1); temp2=LMoveBit(2,8-(2k));//move 4 temp1[i-(k-1)]=temp1[i-(k-1)]+temp2; Buffer[base64b3+(3-k)]=temp1[i-(k-1)]; } } return Buffer; }

  根据这段算法,文章最开始给出的Email内容,可以解码为: 

你好,SnaiX

  这是一个Base64的测试邮件!



  Best Wishes!

base16, base32, base64, base64 URL

基本概念

ASCII 是用128 (2的8次方) 个字符,对二进制数据进行编码的方式

base64编码是用64 (2的6次方) 个字符,对二进制数据进行编码的方式

base32就是用32 (2的5次方) 个字符,对二进制数据进行编码的方式

base16就是用16 (2的4次方) 个字符,对二进制数据进行编码的方式

Base-64编码保证了二进制数据的安全

Base-64编码可以将任意一组字节转换为较长的常见文本字符序列,从而可以合法地作为首部字段值。Base-64编码将用户输入或二进制数据,打包成一种安全格式,将其作为HTTP首部字段的值发送出去,而无须担心其中包含会破坏HTTP分析程序的冒号、换行符或二进制值。

Base-64编码是作为MIME多媒体电子邮件标准的一部分开发的,这样MIME就可以在不同的合法电子邮件网关之间传输富文本和任意的二进制数据里。Base-64编码与将二进制数据文本化表示的uuencode和BinHex标准在本质上类似,但空间效率更高。

1.Base64简介

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。base64编码一般有下面两个用途:

a) 所有的二进制文件,都可以因此转化为可打印的文本编码 (都变成ASCII码可打印字符) ,使用文本软件进行编辑;

b) 能够对文本进行简单的加密。

说白了,一段由0和1组成的串或文件,都能按照base64的编码规则转换成一段由64个字符任意组合的串。

2.Base64编码规则

所谓Base64,就是说选出64个字符–小写字母a-z、大写字母A-Z、数字0-9、符号"+”、"/” (再加上作为垫字的"=”,实际上是65个字符) –作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。

具体来说,转换方式可以分为四步:

第一步,将每三个字节作为一组,一共是24个二进制位

第二步,将这24个二进制位分为四组,每个组有6个二进制位

第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节

第四步,根据下表,得到扩展后的每个字节的对应符号,这就是Base64的编码值

1.Base64是什么:

     Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符 (一般为128-bit的UUID) 编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL (包括隐藏表单域) 中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。

3.规则:

     关于这个编码的规则: 

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

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

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

这样说会不会太抽象了?不用着急,我们来看一个例子:

转换前: aaaaaabb ccccdddd eeffffff

转换后: 00aaaaaa 00bbcccc 00ddddee 00ffffff

应该很清楚了吧?上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。

转换后,我们用一个码表来得到我们想要的字符串 (也就是最终的Base64编码) 。

4.BASE64URL是一种在BASE64的基础上编码形成新的加密方式,为了编码能在网络中安全顺畅传输,需要对BASE64进行的编码,特别是互联网中。

BASE64URL编码的流程:

  1、明文使用BASE64进行加密

 2、在BASE64的基础上进行一下的编码: 

          1)去除尾部的"="

          2)把"+"替换成"-"

          3)把"/"替换成"_"

BASE64URL解码的流程:

 1、把BASE64URL的编码做如下解码: 

          1)把"-"替换成"+"

          2)把"_"替换成"/"

          3)(计算BASE64URL编码长度)%4

                     a)结果为0,不做处理

                     b)结果为2,字符串添加"=="

                     c)结果为3,字符串添加"="

2、使用BASE64解码密文,得到原始的明文

作者: 爱六月的雨

来源: CSDN

原文: https://blog.csdn.net/qq_35725321/article/details/52126402

版权声明: 本文为博主原创文章,转载请附上博文链接!

http://www.voidcn.com/article/p-hsyppdrh-bnz.html

https://blog.csdn.net/wangjianno2/article/details/52464208