本文转载自微信公众号《我是开发者FTD》,作者FTD。转载本文请联系本人。我是开发者FTD公众号。大家好,我是开发者FTD。相信很多同学在工作中经常会用到Base64编码。你知道为什么会有Base64编码吗?我们为什么要使用它,它是如何实现的?让我们深入探讨一下Base64编码吧。在开始Base家族之前,先给大家介绍一下Base家族。尽管我们在工作中使用最多的是Base64,但Base家族不仅仅是Base64。除了Base64,Base家族还包括Base32和Base16。我们都知道ASCII编码。ASCII编码使用256(2的8次方)个字符对二进制数据进行编码。同样的Base64编码使用64个(2的6次方)字符对二进制数据进行编码。编码方式Base32编码使用32个(2的5次方)个字符,Base16编码方式对二进制数据进行编码使用16个(2的4次方)个字符对二进制数据进行编码。Base家族编码形式那么多,为什么要用Base64呢?base64编码使用64个(2的6次方)具体的ASCII字符来表示256个(2的8次方)ASCII字符,也就是说,三个ASCII字符经过Base64编码后,变成四个ASCII字符进行显示(公约数是24)。编码后数据长度比原来增加1/3,小于3n则用“=”补上。Base32编码就是用32个(2的5次方)具体的ASCII字符来表示256个(2的8次方)ASCII码,也就是说5个ASCII字符经过Base32编码后会显示为8个ASCII字符(常见的除数是40)。编码后数据长度比原来增加3/5,小于8n则用“=”补上。Base16编码就是用16个(2的4次方)特定的ASCII字符来表示256(2的8次方)个ASCII字符,也就是说一个ASCII字符经过Base16编码后会变成两个ASCII字符。最终数据长度比原来增加了一倍,如果小于2n,用“=”补上。从上面可以看出,经过Base64编码后,长度增加最少,这也是我们选择Base64的一个重要原因。Base64简介Base64,顾名思义,是一种基于64个可打印字符表示二进制数据的方法,“注意不是加密算法”。对于64个打印字符,我们只需要6个二进制位就可以完全表示它们。那么我们如何使用8个二进制位来表示只能用6个二进制位完全表示的可打印字符呢?由于2的6次方等于64,我们可以以每6位为一个单位,对应一定的可打印字符。三个字节有24位,对应4个Base64单元,即3个字节需要用4个可打印字符表示。Base64是二进制数据到字符的过程。因此,计算机中的所有内容,包括文本、图片、音频、视频等,都可以用Base64编码来表示。Base64编码原理Base64编码是用64个字符作为一个基本字符集:小写字母a-z,大写字母A-Z,数字0-9,符号“+”,“/”(加上“=”作为填充,实际如上是65个字符)然后,所有其他符号都按照一定的规则转换成这个字符集中的字符。具体来说,Base64编码的转换方法可以分为以下四步:第一步,每三个字节为一组,一共是24个二进制位。第二步是将24个二进制位分成四组,每组有6位二进制数。第三步,在每组前面加两个00,扩展为32位二进制数,即4个字节。第四步,根据下表得到每个扩展字节对应的符号,也就是Base64的编码值。Base64编码的字符索引表如下:数字字符数字字符数字字符数字字符0A16Q32g48w1B17R33h49x2C18S34i50y3D19T35j51z4E20U36k5205F21V37l5316G22W38m5427H23X39n5538I24Y40o5649J25Z41p57510K26a42q58611L27b43r59712M28c44s60813N29d45t61914O30e46u62+15P31f47v63/有了这个字符索引表,我们就可以将任何二进制转换成Base64编码。接下来,我们通过几个例子,给大家展示一下转换过程1.假设有一个字符串“FTD”需要转换成base64编码格式第1步:对应的ASCII码值字符“F”、“T”、“D”分别为70、84、68,对应的二进制值为01000110、01010100、01000100。如图中第二行和第三行所示,一个24-位二进制串就这样形成了。第二步:将24位二进制按每组6个二进制位分为四组。第三步:在上面每组前面加两个0展开成32位二进制数,现在变成四个字节:00010001、00100101、00010001、00000100。对应的值(Base64编码索引)分别是:17、37、17、4.第四步:用上面的值在Base64字符索引表中查找,对应:R,I,R,E。所以字符串“FTD”经过Base64编码后变成:RIRE。2、上面例子中的字符正好是三个字节。字节数小于三个怎么办?下面以“F”和“FT”为例进行说明:如上表所示,由于字符F的二进制数为01000110,按照每6位进行分组。这个时候,只能分成一组。第二组缺少4位数字。位数不足,补0;第三组和第四组根本没有数据。然后用**=来弥补。因此,字符F经过Base64编码后得到的值为“Rg==**。3、接下来我们看一下如果只有两个字符的情况:如上表,这也是位数不足需要补齐的情况。第一组和第二组按正常分组计算。第三组位数不足,最后两位用0补全。第四组根本没有数据,用**=补足。因此字符FT经过Base64编码得到的值为“RlQ=**。关于中文的Base64编码,我们都知道中文的编码有很多种,比如“GB2312、GBK、GB18030”。不同的汉字用不同的编码格式编码后,它们的二进制值是不同的,所以经过Base64编码后,它们的Base64编码值也是不同的。这就需要我们在解码的时候注意原文的字符集格式,一定要一致才能正确解码。例如:中文“[我是开发者FTD]公众号”在UTF-8格式Base64编码下的值是:44CQ5oiR5piv5byA5Y+R6ICFRlRE44CR5YWs5LyX5Y+3中文“[我是开发者FTD]公众号”在GB2312格式Base64编码下的最终值是:ob7O0srHv6q3otXfRlREob+5q9bausU=Base64是一种加密算法?base64主要不是用来加密的,它的主要目的是将一些二进制数转换成普通字符进行网络传输,因为有些二进制字符在传输协议中是控制字符,不能直接在网络上传输。此外,有些系统只能使用ASCII字符。Base64编码是一种将非ASCII字符的数据转换成ASCII字符的方法。Base64并不是安全领域的加解密算法,虽然有时也经常看到所谓的Base64加解密算法。其实Base64只能看做是一种编码算法,将数据内容进行编码,使其适合网络传输。虽然经过Base64编码后原文变成了无法理解的字符格式,但是这种编码方式比较初级,非常简单,可以很容易的还原成原文,所以如果有比较重要的信息需要加密,一定要用.文中介绍的加密算法进行数据安全保护。Base64编码实现Java语言中有多个实现Base64编码的库,无论哪个库,最终的结果都是一样的。JDK提供的base64编码实现:publicstaticStringencode(Stringdata){returnBase64.getEncoder().encodeToString(data.getBytes());}publicstaticStringdecode(Stringbase64Data){returnnewString(Base64.getDecoder().decode(base64Data));}BouncyCastle提供的Base64编码实现:publicstaticStringencode(Stringdata){returnnewString(Base64.encode(data.getBytes()));}publicstaticStringdecode(Stringbase64Data){returnnewString(Base64.decode(base64Data));}CommonsCodec提供的Base64编码实现:publicstaticStringencode(Stringdata){returnBase64.encodeBase64String(data.getBytes());}publicstaticStringdecode(Stringbase64Data){returnnewString(Base64.decodeBase64(base64Data));}下面用Java语言的实现来验证一下,我们的第二章是推理正确吗?代码如下:System.out.println("FTbase64编码:"+encode(ft));System.out.println("Fbase64编码:"+encode(f));}输出结果为:FTDbase64编码:RlREFTbase64encoding:RlQ=Fbase64encoding:Rg==可以看到和我们分析的结果完全一样查看完整代码请访问:https://github.com/ForTheDevelopers/JavaSecurityBase64在我们做的工作中经常用到,但是很少有人会去深入研究它的实现原理。如果理解不当,有些人甚至会在业务系统的关键位置将其作为加密和解密,造成严重的后果。相信大家看过上面的内容后,应该对Base64编码有了深刻的理解。
