技术经验分享:base64详解

简介: 技术经验分享:base64详解

base64详解


前置知识


位与字节


二进制系统中,每个0或1就是一个位(bit,比特),也叫存储单元,位是数据存储的最小单位。


其中8bit就称为一个字节(Byte)。


1B=8位


位运算


与运算:符号表示为&。运算规则:两位同时为“1”,结果才为“1”,否则为0或运算:符号表示为|。运算规则:两位只要有一位为“1”,结果就为“1”,否则为0


典型:


0000 0101 : 代表高四位, 代表低四位


char1&0x3:0x3是十六进制数,用二进制表示是0000 0011,用于提取char1的低两位,就是有1的那两位


char2&0xf0:0xf0是一个十六进制数,表示为二进制 11110000,用于提取 char2 的高四位。


移位操作


右移,[左移


// 左移


01101000 [ 2 -> 101000(左侧移出位被丢弃) -> 10100000(右侧空位一律补0)


// 右移


01101000 ] 2 -> 011010(右侧移出位被丢弃) -> 00011010(左侧空位一律补0)


base64编码


base64编码的概念


base64编码就是将字符串以每3个比特(bit)的字节子序列拆分为4个6比特(bit)的字节子序列(这个6比特是有效字节,最左边两个永远为0,其实也算是8比特的字节),再将得到的子序列查找base64的编码索引表,得到对应的字符拼接成新的字符串的一种编码方式。


每3个8比特(bit)的字节子序列拆分成4个6比特(bit)的字节序列的拆分过程如下图所示:


为什么base64编码后的大小是原来的4/3倍


因为6和8的最小公倍数是24,所以3个8比特的字节刚好可以拆分成4个6比特的字节,3 8 = 6 4。计算机中,因为一个字节需要8个存储单元存储,所以我们要把6个比特往前面补两位0,补足8个比特。如下图所示:


很明显,补足后所需的存储单元为32个,是原来所需的24个的4/3倍。现在大家明白为什么base64编码后的大小是原来的4/3倍了吧。


为什么命名为base64呢


因为6位的二进制有2的6次方个,也就是二进制数(0000 0000 - 0011 1111)之间的代表0-63的64个二进制数。


不是说一个字节是用8位二进制表示的吗,为什么不是2的8次方?


因为我们得到的8位二进制数的前两位永远是0,真正的有效位只有6位,所以我们所能够得到的二进制数只有2的6次方个。


base64字符是哪64个


Base64的编码索引表,字符选用了"A-Z、a-z、0-9、+、/" 64个可打印字符来代表(00000000-00111111)这64个二进制数。即


let base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'


编码原理


我们不妨自己先思考一下,要把3个字节拆分成4个字节可以怎么做?你的实现思路和我的实现思路有哪个不同,我们之间又会碰出怎样的火花?


流程图


思路


分析映射关系:a b c -> x y z i


从高位到地位添加索引分析这个过程:


x:(前面补2个0)a的前6位 => 00a【7】a【6】 a【5】a【4】a【3】a【2】


y:(前面补2个0)a的后2位 + b的前4位 => 00a【1】a【0】 b【7】b【6】b【5】b【4】


z:(前面补2个0)b的后4位 + c的前2位 => 00b【3】b【2】 b【1】b【0】c【7】c【6】


i:(前面补2个0)c的后6位 => 00c【5】c【4】 c【3】c【2】c【1】c【0】


通过上面的分析,很容易得到实现思路:


将字符对应的ASCII编码转为8位的二进制


将每三个8位二进制数进行以下操作:


(1)将第一个数右移2位,得到第一个6位有效位二进制数


(2)将第一个数&0x3之后左移4位,得到第二个6位有效位二进制数的第一个和第二个有效位,将第二个数 & 0xf0之后右移位4位,得到第二个6位有效位二进制数的后四位有效位,两者取且得到第二个6位有 效位二进制


(3)将第二个数 & 0xf之后左移位2位,得到第三个6位有效位二进制数的前四位有效位,将第三个数 & 0xC0之后右移位6位,得到第三个6位有效位二进制数的后两位有效位,两者取且得到第三个6位有效 位二进制


(4)将第三个数 & 0x3f,得到第四个6位有效位二进制数


将获得的6位有效位二进制数转十进制,查找对应base64字符


注释:


char1&0x3的计算方法:先将char1和0x3转换为二进制,即0000 0011,按位与,作用是取char1的低两位


& 0xf0,即1111 0000,取高四位


& 0xf ,即0000 1111,取低四位


& 0xC0,即1100 0000,取高两位


& 0x3f ,即0011 1111,取低六位


base64编码实例


0x01


我们以hao字符串为例,观察base64编码的过程,我们将上面转换通过代码逻辑分析实现吧。


编码结果为aGFv


#include


char base64EncodeChars【】 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


int main() {


char str【】="hao";


char char1,char2,char3,out1,out2,out3,out4;


char out【5】;


// 将字符对应的ASCII值转为8位二进制数,& 0xff是为了保留8位二进制


char1 = str【0】 & 0xff; // h 的ASCII为 104 二进制为 01101000


char2 = str【1】 & 0xff; // a 的ASCII为 97 二进制为 01100001


char3 = str【2】 & 0xff; // o 的ASCII为 111 二进制为 01101111


// 输出6位有效字节二进制数


out1 = char1 ] 2; // 26 011010


out2 = (char1 & 0x3) [ 4 | (char2 & 0xf0) ] 4; // 6 000110


out3 = (char2 & 0xf) [ 2 | (char3 & 0xc0) ] 6; // 5 000101


out4 = char3 & 0x3f; // 47 101111


out【0】 = base64EncodeChars【out1】; //输出out1对应的ASCII


out【1】 = base64EncodeChars【out2】; //输出out2对应的ASCII


out【2】 = base64EncodeChars【out3】; //输出out3对应的ASCII


out【3】 = base64EncodeChars【out4】; //输出out4对应的ASCII


out【4】 = '\0'; //去掉输出末尾的'hao'


printf("%s",out);


return 0;


}


0x02


扩展至多字符字符串


#include


#include[span style="color: rgba(0, 0, 255, 1)">string.h>


char base64EncodeChars【】="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;


int main(){


char str【】="haohaohao";


char char1,char2,char3,out1,out2,out3,out4;


char out【100】;


int len = strlen(str);


int index = 0;


int outindex = 0;


while(index [span style="color: rgba(0, 0, 0, 1)"> len){


char1 = str【index++】 & 0xff ;


char2 = str【index++】 & 0xff ;


char3 = str【index++】 & 0xff ;


out1 = char1 ] 2 ;


out2 = (char1 & 0x3) [ 4 | (char2 & 0xf0) ] 4 ;


out3 = (char2 & 0xf) [ 2 | (char3 & 0xc0) ] 6 ;


out4 = char3 & 0x3f ;


out【outindex++】 = base64EncodeChars【out1】;


out【outindex++】 = base64EncodeChars【out2】;


out【outindex++】 = base64EncodeChars【out3】;


out【outindex++】 = base64EncodeChars【out4】;


}


out【outindex】 = '\0';


printf("%s\n",out);


return 0;


}


0x03


究极版base64编码


#include


#include


char base64Encode(const char str) {


// Base64 characters


const char base64EncodeChars【】 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


// Get string length


int len = 0;


while (str【len】 != '\0') {


len++;


}


// Output string


char out = (char)malloc(len 4 / 3 + 4);


char v11 = out;


int index = 0;


while (index [span style="color: rgba(0, 0, 0, 1)"> len) {


// Define input and output bytes


unsigned char char1, char2, char3;


unsigned char out1, out2, out3, out4;


// Convert characters to ASCII codes


char1 = str【index++】 & 0xff;


out1 = char1 ] 2;


if (index == len) {


out2 = (char1 & 0x3) [ 4;


sprintf(v11, "%c%c==", base64EncodeChars【out1】, base64EncodeChars【out2】);


break;


}


char2 = str【index++】 & 0xff;


out2 = ((char1 & 0x3) [ 4) | ((char2 & 0xf0) ] 4);


if (index == len) {


out3 = (char2 & 0xf) [ 2;


sprintf(v11, "%c%c%c=", base64EncodeChars【out1】, base64EncodeChars【out2】, base64EncodeChars【out3】);


break;


}


char3 = str【index++】 & 0xff;


out3 = ((char2 & 0xf) [ 2) | ((char3 //代码效果参考:http://www.jhylw.com.cn/423938089.html

& 0xc0) ] 6);

out4 = char3 & 0x3f;


sprintf(v11, "%c%c%c%c", base64EncodeChars【out1】, base64EncodeChars【out2】, base64EncodeChars【out3】, base64EncodeChars【out4】);


v11 += 4;


}


return out;


}


int main() {


char encodedStr = base64Encode("haohao");


printf("%s\n", encodedStr);


free(encodedStr);


encodedStr = base64Encode("haoha");


printf("%s\n", encodedStr);


free(encodedStr);


encodedStr = base64Encode("haoh");


printf("%s\n", encodedStr);


free(encodedStr);


return 0;


}


base64自定义字符编码


#include


#include


char base64Encode(const char str) {


// Base64 characters


const char base64EncodeChars【】 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


// Get string length


int len = 0;


while (str【len】 != '\0') {


len++;


}


// Output string


char out = (char)malloc(len 4 / 3 + 4);


char* v11 = out;


int index = 0;


while (index [span style="color: rgba(0, 0, 0, 1)"> len) {


// Define input and output bytes


unsigned char char1, char2, char3;


unsigned char out1, out2, out3, out4;


// Convert characters to ASCII codes


char1 = str【index++】 & 0xff;


out1 = char1 ] 2;


if (index == len) {


out2 = (char1 & 0x3) [ 4;


sprintf(v11, "%c%c==", base64EncodeChars【out1】, base64EncodeChars【out2】);


break;


}


char2 = str【index++】 & 0xff;


out2 = ((char1 & 0x3) [ 4) | ((char2 & 0xf0) ] 4);


if (index == len) {


out3 = (char2 & 0xf) [ 2;


sprintf(v11, "%c%c%c=", base64EncodeChars【out1】, base64EncodeChars【out2】, base64EncodeChars【out3】);


break;


}


char3 = str【index++】 & 0xff;


out3 = ((char2 & 0xf) [ 2) | ((char3 & 0xc0) ] 6);


out4 = char3 & 0x3f;


sprintf(v11, "%c%c%c%c", base64EncodeC

相关文章
|
2月前
技术经验分享:comparisonmethodviolates必现
技术经验分享:comparisonmethodviolates必现
12 0
技术经验分享:comparisonmethodviolates必现
|
2月前
|
机器学习/深度学习 存储 人工智能
人工智能平台PAI产品使用合集之filePath该如何写
阿里云人工智能平台PAI是一个功能强大、易于使用的AI开发平台,旨在降低AI开发门槛,加速创新,助力企业和开发者高效构建、部署和管理人工智能应用。其中包含了一系列相互协同的产品与服务,共同构成一个完整的人工智能开发与应用生态系统。以下是对PAI产品使用合集的概述,涵盖数据处理、模型开发、训练加速、模型部署及管理等多个环节。
|
2月前
|
人工智能
技术经验分享:CF223C
技术经验分享:CF223C
12 0
|
2月前
|
存储 安全 物联网
技术经验分享:FIDO标准简介
技术经验分享:FIDO标准简介
|
3月前
|
JavaScript Java 测试技术
基于Java的交流论坛的设计与实现(源码+lw+部署文档+讲解等)
基于Java的交流论坛的设计与实现(源码+lw+部署文档+讲解等)
48 0
|
3月前
|
JavaScript Java 测试技术
基于Java的影视创作论坛的设计与实现(源码+lw+部署文档+讲解等)
基于Java的影视创作论坛的设计与实现(源码+lw+部署文档+讲解等)
38 0
|
8月前
|
存储 前端开发 算法
了不起的Base64
了不起的Base64
《圆桌讨论: 从趋势、工具或相关的技术点谈APP的优化》电子版地址
圆桌讨论: 从趋势、工具或相关的技术点谈APP的优化
52 0
《圆桌讨论: 从趋势、工具或相关的技术点谈APP的优化》电子版地址
DHL
|
XML 存储 算法
[译][Google工程师] 详解 FragmentFactory 如何优雅使用 Koin 以及部分源码分析
继续上一篇文章,介绍一下 FragmentFactory 和 FragmentContainerView 以及如何和 Koin 一起使用, 这是 Google 在 Fragment 1.2.0 上做的重要的更新,强烈建议大家去使用
DHL
456 0
[译][Google工程师] 详解 FragmentFactory 如何优雅使用 Koin 以及部分源码分析
【愚公系列】2021年11月 攻防世界-进阶题-MISC-001(base64÷4)
【愚公系列】2021年11月 攻防世界-进阶题-MISC-001(base64÷4)
112 0
【愚公系列】2021年11月 攻防世界-进阶题-MISC-001(base64÷4)