30功能之Base64编码原理

2023-11-05

一 Base64的由来

目前Base64已经成为网络上常见的传输8Bit字节代码的编码方式之一。在做支付系统时,系统之间的报文交互都需要使用Base64对明文进行转码,然后再进行签名或加密,之后再进行(或再次Base64)传输。那么,Base64到底起到什么作用呢?

在参数传输的过程中经常遇到的一种情况:使用全英文的没问题,但一旦涉及到中文就会出现乱码情况。与此类似,网络上传输的字符并不全是可打印的字符,比如二进制文件、图片等。Base64的出现就是为了解决此问题,它是基于64个可打印的字符来表示二进制的数据的一种方法。

电子邮件刚问世的时候,只能传输英文,但后来随着用户的增加,中文、日文等文字的用户也有需求,但这些字符并不能被服务器或网关有效处理,因此Base64就登场了。随之,Base64在URL、Cookie、网页传输少量二进制文件中也有相应的使用。

二 Base64的编码原理

Base64的原理比较简单,每当我们使用Base64时都会先定义一个类似这样的数组:

static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

上面就是Base64的索引表,字符选用了"A-Z、a-z、0-9、+、/" 64个可打印字符,这是标准的Base64协议规定。在日常使用中我们还会看到“=”或“==”号出现在Base64的编码结果中,“=”在此是作为填充字符出现,后面会讲到。

1 具体转换步骤:

  • 1)第一步,将待转换的字符串每三个字节分为一组,每个字节占8bit,那么共有24个二进制位。
  • 2)第二步,将上面的24个二进制位每6个一组,共分为4组。
  • 3)第三步,在每组前面添加两个0,每组由6个变为8个二进制位,总共32个二进制位,即四个字节。
  • 4)第四步,根据Base64编码对照表(见下图)获得对应的值。

在这里插入图片描述
从上面的步骤我们发现:

  • 1)Base64字符表中的字符原本用6个bit就可以表示,现在前面添加2个0,变为8个bit,会造成一定的浪费。因此,Base64编码之后的文本,要比原文大约三分之一。
  • 2)为什么使用3个字节一组呢?因为6和8的最小公倍数为24,三个字节正好24个二进制位,每6个bit位一组,恰好能够分为4组。

三 示例说明

以下图的表格为示例,我们具体分析一下整个过程。
注意:对于下面的表格和代码的演示,我们使用电脑自带的计算器计算即可,非常非常方便,也赖得自己算,win+r输入calc,然后选择程序员即可。
在这里插入图片描述

  • 1)第一步:“M”、“a”、"n"对应的ASCII码值分别为77,97,110,对应的二进制值是01001101、01100001、01101110。如图第二三行所示,由此组成一个24位的二进制字符串。
  • 2)第二步:如图红色框,将24位每6位二进制位一组分成四组。
  • 3)第三步:在上面每一组前面补两个0,扩展成32个二进制位,此时变为四个字节:00010011、00010110、00000101、00101110。分别对应的值(Base64编码索引)为:19、22、5、46。
  • 4)第四步:用上面的值在Base64编码表中进行查找,分别对应:T、W、F、u。因此“Man”Base64编码之后就变为:TWFu。

位数不足情况:
上面是按照三个字节来举例说明的,如果字节数不足三个,那么该如何处理?
在这里插入图片描述

  • 1)两个字节:两个字节共16个二进制位,依旧按照规则进行分组。此时总共16个二进制位,每6个一组,则第三组缺少2位,用0补齐,得到三个Base64编码,第四组完全没有数据则用“=”补上。因此,上图中“BC”转换之后为“QKM=”。
  • 2)一个字节:一个字节共8个二进制位,依旧按照规则进行分组。此时共8个二进制位,每6个一组,则第二组缺少4位,用0补齐,得到两个Base64编码,而后面两组没有对应数据,都用“=”补上。因此,上图中“A”转换之后为“QQ==”。

注意事项:

  • 1)大多数编码都是由字符串转化成二进制的过程,而Base64的编码则是从二进制转换为字符串。与常规恰恰相反,
  • 2)Base64编码主要用在传输、存储、表示二进制领域,不能算得上加密,只是无法直接看到明文。也可以通过打乱Base64编码来进行加密。
  • 3)中文有多种编码(比如:utf-8、gb2312、gbk等),不同编码对应Base64编码结果都不一样。

延伸:
上面我们已经看到了Base64就是用6位(2的6次幂就是64)表示字符,因此成为Base64。同理,Base32就是用5位,Base16就是用4位。大家可以按照上面的步骤进行演化一下。

四 代码演示

强调,必须拿代码去调试,在调试过程中让编译器帮我们一起理解每一行代码,比纯看代码学习快速很多。

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <vector>
#include <map>
#include <thread>
#include <string>
#include <sstream>
#include <mutex>
#include <Windows.h>

using namespace std;

#define AV_BASE64_SIZE(x)  (((x) + 2) / 3 * 4 + 1)
char *av_base64_encode(char *out, int out_size, const unsigned char *in, int in_size)
{
	static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	char *ret, *dst;
	unsigned i_bits = 0;
	int i_shift = 0;
	int bytes_remaining = in_size;

	if (in_size >= (0x7fffffff / 4) || out_size < AV_BASE64_SIZE(in_size))//这里条件限制有空再研究
	{
		return NULL;
	}

	ret = out;// 保存首地址
	dst = out;// 用于操作
	while (bytes_remaining)
	{
		i_bits = (i_bits << 8) + *in;//或者*in++,将下一句in++省略,这里i_bits每次累加保存3个字节转成base64的4字节的二进制位,这样就可以去到对应的6位二进制。
		in++;
		bytes_remaining--;
		i_shift += 8;// 要想下面每次左移6位后,想在前面补2个0,所以每次右移时都得叠加2.例如字符M,x<<6,x需要>>8.字符a,x<<6,x需要>>8+2,因为需要跳过原来的M的8位。

		do {
			*dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f];// 每次左移6位到高位,然后再右移8位,实际就是补2个0.对着表格理解即可。
			i_shift -= 6;
		} while (i_shift > 6 || (bytes_remaining == 0 && i_shift > 0));// dowhile满足就继续,不满足就退出
	}
	while ((dst - ret) & 3)
		*dst++ = '=';
	*dst = '\0';

	return ret;
}
int main(){

	string man = "Man";
	string a = "A";
	string bc = "BC";
	char str_sps[100] = { 0 };
	av_base64_encode(str_sps, 100, reinterpret_cast<const unsigned char*>(man.c_str()), man.length());
	cout << "man's basecode: " << str_sps << endl;

	memset(str_sps, 0x00, 100);
	av_base64_encode(str_sps, 100, reinterpret_cast<const unsigned char*>(a.c_str()), a.length());
	cout << "a's basecode: " << str_sps << endl;

	memset(str_sps, 0x00, 100);
	av_base64_encode(str_sps, 100, reinterpret_cast<const unsigned char*>(bc.c_str()), bc.length());
	cout << "bc's basecode: " << str_sps << endl;

	/*cout << "主线程结束" << endl;*/

	return 0;
}

结果:
在这里插入图片描述
以上结果与我们分析所得完全一致。

参考文章:一篇文章彻底弄懂Base64编码原理

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

30功能之Base64编码原理 的相关文章

  • VLC 媒体播放器有 C# 界面吗? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否可以使用 C 控制台应用程序中的包装器从 VLC 播放中当前播放的文件中读取曲目统计信息 时间 标
  • 捕获 .aspx 和 .ascx 页面中的异常

    问题说明了一切 请看以下示例代码 ul li li ul
  • 如何使用 openSSL 函数验证 PEM 证书的密钥长度

    如何验证以这种方式生成的 PEM 证书的密钥长度 openssl genrsa des3 out server key 1024 openssl req new key server key out server csr cp server
  • Boost ASIO 串行写入十六进制值

    我正在使用 ubuntu 通过串行端口与设备进行通信 所有消息都必须是十六进制值 我已经在 Windows 环境中使用白蚁测试了通信设置 并得到了我期望的响应 但在使用 Boost asio 时我无法得到任何响应 以下是我设置串口的方法 b
  • 在 Mono 中反序列化 JSON 数据

    使用 Monodroid 时 是否有一种简单的方法可以将简单的 JSON 字符串反序列化为 NET 对象 System Json 只提供序列化 不提供反序列化 我尝试过的各种第三方库都会导致 Mono Monodroid 出现问题 谢谢 f
  • 混合模型优先和代码优先

    我们使用模型优先方法创建了一个 Web 应用程序 一名新开发人员进入该项目 并使用代码优先方法 使用数据库文件 创建了一个新的自定义模型 这 这是代码第一个数据库上下文 namespace WVITDB DAL public class D
  • MVC 5 中具有 ASP.NET Identity 的 Autofac 不会验证 OWIN 管道中的安全标记

    我在 MVC 5 中设置了 AutoFac 来与 ASP NET Identity 一起使用 表面上一切似乎都工作正常 即用户可以创建帐户并登录 但后来我发现 当安全标记更改时 用户不会注销 通过在 AspNetUsers 表中进行暴力破解
  • if constexpr 中的 not-constexpr 变量 – clang 与 GCC

    struct A constexpr operator bool const return true int main auto f auto v if constexpr v A a f a clang 6 接受该代码 GCC 8 拒绝它
  • LinkLabel 无下划线 - Compact Framework

    我正在使用 Microsoft Compact Framework 开发 Windows CE 应用程序 我必须使用 LinkLabel 它必须是白色且没有下划线 因此 在设计器中 我将字体颜色修改为白色 并在字体对话框中取消选中 下划线
  • 条件类型定义

    如果我有一小段这样的代码 template
  • 在 azure blob 存储中就地创建 zip 文件

    我将文件存储在 Blob 存储帐户内的一个容器中 我需要在第二个容器中创建一个 zip 文件 其中包含第一个容器中的文件 我有一个使用辅助角色和 DotNetZip 工作的解决方案 但由于 zip 文件的大小最终可能达到 1GB 我担心在进
  • 如何从 Boost.PropertyTree 复制子树

    我有一些boost property tree ptree 我需要树来删除一些具有特定标签名称的元素 例如 xml 表示源ptree如下
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • 当Model和ViewModel一模一样的时候怎么办?

    我想知道什么是最佳实践 我被告知要始终创建 ViewModel 并且永远不要使用核心模型类将数据传递到视图 这就说得通了 让我把事情分开 但什么是Model 和ViewModel一模一样 我应该重新创建另一个类还是只是使用它 我觉得我应该重
  • .NET 和 Mono 之间的开发差异

    我正在研究 Mono 和 NET C 将来当项目开发时我们需要在 Linux 服务器上运行代码 此时我一直在研究 ASP NET MVC 和 Mono 我运行 Ubuntu 发行版 想要开发 Web 应用程序 其他一些开发人员使用 Wind
  • Unity3D - 将 UI 对象移动到屏幕中心,同时保持其父子关系

    我有一个 UI 图像 它的父级是 RectTransform 容器 该容器的父级是 UI 面板 而 UI 面板的父级是 Canvas 我希望能够将此 UI 图像移动到屏幕中心 即画布 同时保留父级层次结构 我的目标是将 UI 图像从中心动画
  • 在哪里可以找到 Microsoft.Build.Utilities.v3.5

    如何获取 Microsoft Build Utilities v3 5 我正在使用 StyleCop 4 7 Stylecop dll 中的 StyleCop msbuild 任务似乎依赖于 Microsoft Build Utilitie
  • 在 C# 的 WebAPI 中的 ApiController 上使用“传输编码:分块”提供数据

    我需要服务分块传输使用编码数据API控制器 因为我无权访问HttpContext or the Http请求 我有点不知道在哪里写入响应以及在哪里刷新它 设置如下 public class MyController ApiControlle
  • 如何组合两个 lambda [重复]

    这个问题在这里已经有答案了 可能的重复 在 C 中组合两个 lambda 表达式 https stackoverflow com questions 1717444 combining two lamba expressions in c
  • Streamwriter 覆盖 txt 文件中的文本

    有没有什么方法可以重新打开流写入器而不创建新的写入对象 因为此时 当调用 WriteOdd 时 streamwriter 正在覆盖在它之前调用的 WriteEven public void WriteEven StreamWriter wr

随机推荐

  • 【C语言/C++_数组长度问题】如何获取数组长度?

    problem 我们怎么获取数组长度 常规数组 int float double 我们怎么获取字符串数组长度 字符串数组 未完待续 Solution 1 使用sizeof 函数 获取所求数组的的总大小 再获取该数组中单个元素所占空间大小 进
  • Windows 10 系统服务的 “自动(延迟启动)” 时间

    简而言之 设置为Automatic的服务将在引导过程中启动 而设置为Delayed的服务将在引导后立即启动 启动服务延迟可以提高服务器的启动性能 并且具有安全性优势 这些优势在Adriano的文章中列出 默认情况下 自动 延迟启动 实际上是
  • 牛客网Verilog快速入门题目收获——异步复位的串联T触发器(VL2)

    一 题目要求 给出信号示意图以及波形示意图 用verilog实现两个串联的异步复位的T触发器的逻辑 二 完成题目前的知识储备 1 书写规范 根据verilog代码书写规范 低电平复位信号用 rst n 高电平复位用rst 这里题目低电平复位
  • 优秀的框架stylefeng——guns/roses

    Guns基于SpringBoot 致力于做更简洁的后台管理系统 完美整合springmvc shiro mybatis plus beetl Guns项目代码简洁 注释丰富 上手容易 同时Guns包含许多基础模块 用户管理 角色管理 部门管
  • 平均年薪超105万元,区块链开发待遇这么高?

    近段时间 没有比 区块链 更火的词了 2019年10 月 24 日时国家就区块链技术发展现状与趋势进行第十八次集体学习 学习时着重强调 区块链技术的集成应用在新的技术革新和产业变革中起到重要作用 这意味着区块链技术将加速与产业的融合 也就是
  • 【形形色色的卷积】差分卷积

    文章目录 0 前言 1 中心差分卷积 2 像素差分卷积 3 参考 0 前言 普通卷积不能显式地提取图像的梯度信息 因此不能较好地描述细粒度的纹理信息 在人脸活体检测 边缘检测等对细粒度纹理信息敏感的任务中难以取得理想的结果 针对上述问题 O
  • 梁乾东:4.10黄金下周涨跌怎么看?黄金原油最新策略解析

    黄金下周行情解析 周五 4月9日 上海黄金交易所收涨0 54 报370 11元 克 白银T D收涨0 71 报5267元 公斤 金价收高 主要由于美债收益率下跌 美元短线走弱 也给金价带来短期支撑 但由于全球经济复苏良好 这始终对金价构成下
  • idea报错一个包找不到另一个包 com.j8.enity.User cannot be cast to com.j8.enity.lx

    要注意自己定义的类是否是正确的 否则就会出现这样的错误
  • 阿里天池-全球数据智能大赛

    里面的数据解析 https tianchi aliyun com forum issueDetail spm 5176 12282029 0 0 1549467d4xr1bT postId 62363 用NotePad 或其他的软件打开se
  • 鸽巢算法

    该算法主要用来对给定数据集进行排序的 可以快速求出第N大的数字 时间为常数时间 缺点 数据的范围不能太大 步骤如下 1 给定一个待排序数组 相当于一群鸽子 创建一个备用数组 叫鸽巢数组 并初始化元素为0 备用数组的索引 鸽巢的编号 即是待排
  • 让人工智能机器人学会自我情绪管理

    人类微观管理的一个影响是显而易见的 它会减慢速度 人类也是如此 一个不得不向上级请求命令的人类士兵的反应会比一个有权采取主动的人反应更慢 这对人工智能来说是一个更大的刹车 机器人教育课件它的电子思维过程比人类的神经化学大脑循环要快得多 一个
  • 超详细的Node.js环境搭建

    在使用Node js前 我们需要先进行Node js安装和配置 1 下载 Node js官网地址 https node js org 从官网上可以看到有两个版本的安装包 14 15 1和15 3 0 15 3 0是当前最新版 14 15 1
  • a-table及相关组件的使用

    a table及相关组件的使用 基础的渲染
  • 第38.1节 osg加载大tif-编译vpb

    目录 本节内容 具体内容 本节内容 本节开始实现使用osg加载超大tif的功能 具体有多大的tif可以支持呢 就是要多大有多大 要不是网友们提这个功能 我基本上已经忘记vpb了 它是osg早期关于使用影像和高程大图来生成瓦片地形的这么一个工
  • DeepSpeed 部署中bug以及解决方法

    text generation 1 can t find Rust compiler 在Linux上安装Rust 您可以使用curl或者类似包管理器的工具来安装Rust 使用curl命令安装Rust和Cargo curl proto htt
  • java基础:内部类

    内部类 1 简介 大部分时候 类被定义为一个独立的程序单元 在某些情况下 也会把一个类放在另外一个类的内部定义 这种类就被称为内部类 嵌套类 包含内部类的类也被称为外部类 宿主类 2 作用 内部类提供了更好的封装 可以将内部类隐藏在外部类之
  • 图片上传怎么搞?!阿里云OSS对象存储教你快速实现!

    一 需求背景 小白 辉哥 我想在项目中实现图片上传 不知道有没有好用的第三方文件上传技术呢 辉哥 那多了去了 阿里 腾讯 百度 七牛云等都有文件上传技术 你从中随便挑一个 辉哥这就给你安排 小白 阿里也有文件上传 要不辉哥就给我安排阿里的实
  • Spring Boot 读取配置文件的五种方式

    第一种 Value 方式读取 前提条件 在application properties 文件中 写入相关属性值 customer address USA 读取工具类源码 Component public class CustonerConf
  • Java面试整理(二)《JavaSE》

    JavaSE 说明 我会根据我自己的经验 给每个内容标注重要程度 共有三个等级 低 中 高 仅个人参考意见 JVM是什么 中 JVM是Java Virtual Machine的缩写 是用于运行Java字节码的虚拟机 JVM是运行在操作系统之
  • 30功能之Base64编码原理

    一 Base64的由来 目前Base64已经成为网络上常见的传输8Bit字节代码的编码方式之一 在做支付系统时 系统之间的报文交互都需要使用Base64对明文进行转码 然后再进行签名或加密 之后再进行 或再次Base64 传输 那么 Bas