Base64编码原理

news/2024/10/30 17:20:26/文章来源:https://www.cnblogs.com/hnu-hua/p/18516202

Base64编码原理

Base64作用

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

Base64编码原理

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

['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']

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

具体转换步骤

  • 第一步,将待转换的字符串每三个字节分为一组,每个字节占8bit,那么共有24个二进制位。
  • 第二步,将上面的24个二进制位每6个一组,共分为4组。
  • 第三步,在每组前面添加两个0,每组由6个变为8个二进制位,总共32个二进制位,即四个字节。
  • 第四步,根据Base64编码对照表(见下图)获得对应的值。
0 A  17 R   34 i   51 z1 B  18 S   35 j   52 02 C  19 T   36 k   53 13 D  20 U   37 l   54 24 E  21 V   38 m   55 35 F  22 W   39 n   56 46 G  23 X   40 o   57 57 H  24 Y   41 p   58 68 I  25 Z   42 q   59 79 J  26 a   43 r   60 810 K  27 b   44 s   61 911 L  28 c   45 t   62 +12 M  29 d   46 u   63 /13 N  30 e   47 v14 O  31 f   48 w   15 P  32 g   49 x16 Q  33 h   50 y

从上面的步骤我们发现:

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

示例说明

以下图的表格为示例,我们具体分析一下整个过程。

在这里插入图片描述

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

位数不足情况

上面是按照三个字节来举例说明的,如果字节数不足三个,那么该如何处理?

在这里插入图片描述

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

注意事项

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

Base64代码实现

  • python
class MyBase64():base64_dict = {}string_temp = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ''abcdefghijklmnopqrstuvwxyz''0123456789+/')ascii_string = ''.join([chr(i) for i in range(4, 2 ** 7 - 1)])def __init__(self, string):# 初始化,创建 base64 编码字典self.string = stringfor i in range(2 ** 6):self.base64_dict[i] = self.string_temp[i]def convert(self):# base64 编码过程# 编码string_encode_byte = self.string.encode('utf-8')# 十进制化string_digit_list = list(string_encode_byte)# 二进制化 + 0 填充string_bin_list = []for item in string_digit_list:string_bin_list.append(str(bin(item))[2:].zfill(8))# 字符串合并string_sum = ''.join(string_bin_list)# 6 的倍数,不足 0 填充string_fill = self.fillIt(string_sum, factor=6, item='0')# 切片,6位一个单位string_bin_list2 = self.splitIt(string_fill, bits=6)# 十进制化string_digit_list2 = []for item in string_bin_list2:string_digit_list2.append(int(item, 2))# 查表string_base64_list = []for item in string_digit_list2:string_base64_list.append(self.base64_dict[item])# 拼接string_sum2 = ''.join(string_base64_list)# 4 的倍数,不足填充 =string_convert = self.fillIt(string_sum2, factor=4, item='=')return string_convertdef fillIt(self, string, factor, item):"""指定倍数填充指定字符string:原字符串factor:倍数item:填充字符"""length = len(string)remainder = length % factorif remainder:times = factor - remainderstring = string + times * itemreturn stringdef splitIt(self, string, bits):"""指定位数切片string:原字符串bits:每次切片数量"""length = len(string)new_list = []for i in range(bits, length + 1, bits):new_list.append(string[i - bits:i])remain = length % bitsif remain != 0:new_list.append(string[-remain:])return new_listif __name__ == '__main__':string = input()myBase64 = MyBase64(string)enc_string = myBase64.convert()print("测试字符串:{}".format(string))print("base64:{}".format(enc_string))
  • c
// base64.cpp
#include <iostream>
#include <windows.h>
#include "Base64.h"using namespace std;char *base64_encode(const char* data, int data_len) 
{ //int data_len = strlen(data); int prepare = 0; int ret_len; int temp = 0; char *ret = NULL; char *f = NULL; int tmp = 0; char changed[4]; int i = 0; ret_len = data_len / 3; temp = data_len % 3; if (temp > 0) { ret_len += 1; } ret_len = ret_len*4 + 1; ret = (char *)malloc(ret_len); if ( ret == NULL) { printf("No enough memory.\n"); exit(0); } memset(ret, 0, ret_len); f = ret; while (tmp < data_len) { temp = 0; prepare = 0; memset(changed, '\0', 4); while (temp < 3) { //printf("tmp = %d\n", tmp); if (tmp >= data_len) { break; } prepare = ((prepare << 8) | (data[tmp] & 0xFF)); tmp++; temp++; } prepare = (prepare<<((3-temp)*8)); //printf("before for : temp = %d, prepare = %d\n", temp, prepare); for (i = 0; i < 4 ;i++ ) { if (temp < i) { changed[i] = 0x40;          // 瀵瑰簲鐮佽〃涓殑 '=' } else { changed[i] = (prepare>>((3-i)*6)) & 0x3F; } *f = base[changed[i]]; //printf("%.2X", changed[i]); f++; } } *f = '\0'; return ret; } static char find_pos(char ch)   
{ char *ptr = (char*)strrchr(base, ch);//the last position (the only) in base[] return (ptr - base); 
} char *base64_decode(const char *data, int data_len) 
{ int ret_len = (data_len / 4) * 3; int equal_count = 0; char *ret = NULL; char *f = NULL; int tmp = 0; int temp = 0;int prepare = 0; int i = 0; if (*(data + data_len - 1) == '=') { equal_count += 1; } if (*(data + data_len - 2) == '=') { equal_count += 1; } if (*(data + data_len - 3) == '=') {//seems impossible equal_count += 1; } switch (equal_count) { case 0: ret_len += 4;//3 + 1 [1 for NULL] break; case 1: ret_len += 4;//Ceil((6*3)/8)+1 break; case 2: ret_len += 3;//Ceil((6*2)/8)+1 break; case 3: ret_len += 2;//Ceil((6*1)/8)+1 break; } ret = (char *)malloc(ret_len); if (ret == NULL) { printf("No enough memory.\n"); exit(0); } memset(ret, 0, ret_len); f = ret; while (tmp < (data_len - equal_count)) { temp = 0; prepare = 0; while (temp < 4) { if (tmp >= (data_len - equal_count)) { break; } prepare = (prepare << 6) | (find_pos(data[tmp])); temp++; tmp++; } prepare = prepare << ((4-temp) * 6); for (i=0; i<3 ;i++ ) { if (i == temp) { break; } *f = (char)((prepare>>((2-i)*8)) & 0xFF); f++; } } *f = '\0'; return ret; 
}int main() {char text[200];printf("请输入待加密字符:");int i=0;do{scanf("%s",&text[i]); i++;}while(getchar()!='\n');printf("%s\n", base64_encode(text, strlen(text)));return 0;
}
// base64.h#ifndef BASE64_H
#define BASE64_Hconst char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; char* base64_encode(const char* data, int data_len); char* base64_decode(const char* data, int data_len); #endif

参考博客:

一篇文章彻底弄懂Base64编码原理-CSDN博客

base64加密原理及python、C语言代码实现_base加密-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/824227.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

项目管理平台实操:项目经理如何快速生成项目报告?(3分钟教程)

一、项目管理平台与报告生成的关联 项目管理平台在项目管理中起着至关重要的作用。它为项目经理提供了一个集中化的管理工具,能够有效地组织和协调项目的各个方面。 首先,项目管理平台可以实现对项目任务的全面管理。通过任务清单功能,项目经理可以清晰地了解每个任务的名称…

游戏平台如何通过技术加持“弯道超车”

随着游戏产业的蓬勃发展,游戏平台与游戏开发引擎之间的兼容性问题日益凸显。为了满足日益多样化的游戏需求,游戏平台在技术上不断创新,力求实现与各大游戏开发引擎的无缝对接。自从微信2017年12月发布了第一款小游戏--“跳一跳”,小游戏以其“轻量化”、“即用即走”的特性…

试用期被裁是有补偿的!一定要记得领取~

每年都会收到同学试用期被裁的消息,除了震惊之外,更多的是遗憾。 因为试用期被裁的大部分同学都是知名公司的 Offer,例如下面这两个,一个某程旅行,一个某知名外企:某知名外企:所以,本文要聊两个问题:试用期被裁有没有补偿? 如何避免试用期被裁?1.试用期被裁有没有补…

# [Educational Codeforces Round 171](https://codeforces.com/contest/2026)

Educational Codeforces Round 171 D. Sums of Segments定义四个前缀和: \(s_i=a_1+a_2+\dots+a_i\) \(u_i=s_1+s_2+\dots+s_i\) \(t_i=s(i,i)+s(i,i+1)+\dots+s(i,n)\) \(ts_i=t_1+t_2+\dots+t_i\) \(s_i\)为\(a_i\)的前缀和,\(u_i\)为\(s_i\)的前缀和,\(t_i\)为分块之后第…

Ansible 的主机清单和配置文件

一.简介 在使用Ansible来批量管理主机的时候通常我们需要先定义要管理哪些主机或者主机组,而这个用于管理主机与主机组的文件就叫做 Inventory ,也叫主机清单。 该文 件 默 认 位 于/etc/ansible/hosts。当然我们也可以通过修改ansible配置文件的Inventory配置项来修改默认in…

2024年项目经理必看!项目管理平台如何助力项目成功交付?

一、项目管理平台的重要性 在 2024 年,项目管理平台对于项目成功交付起着至关重要的作用。 首先,项目管理平台能够极大地提高协作效率。例如,像 禅道 这样的优秀平台,为团队提供了统一的协作空间,成员可以在平台上共享文档、讨论问题、分配任务等。通过这种方式,信息传递…

嗅探与欺诈实验

作业题目 包嗅探和欺骗是网络安全中的两个重要概念;它们是网络通信中的两大威胁。能够理解这两种威胁对于理解网络中的安全措施至关重要。有许多包嗅探和欺骗工具,如Wireshark、Tcpdump、Netwox等。其中一些工具被安全专家以及攻击者广泛使用。能够使用这些工具对学生来说很重…

强势建议收藏!2024年工程项目管理平台上的10个高效工具

一、多功能的禅道 禅道作为工程项目管理平台,拥有众多强大功能。 在项目管理和协作方面,禅道集成了产品管理、项目管理、质量管理、文档管理、组织管理和事务管理等多方面功能,完整覆盖了工程项目管理的核心流程。通过禅道,团队成员可以清晰地了解项目的各个环节,从需求收…

TCP攻击实验

作业题目 本实验的学习目标是让学生获得有关漏洞以及针对这些漏洞的攻击的第一手经验。聪明人从错误中学习。在安全教育中,我们研究导致软件漏洞的错误。研究过去的错误不仅有助于学生理解为什么系统容易受到攻击,为什么“看似良性”的错误会变成灾难,以及为什么需要许多安全…

环境变量与set-uid实验

作业题目 本实验室的学习目标是让学生了解环境变量如何影响程序以及系统行为。环境变量是一组动态命名值,可以影响正在运行的进程将在计算机上运行。大多数操作系统都使用它们,因为它们是1979年引入Unix。尽管环境变量会影响程序行为,但它们是如何实现的这一点很多程序员都不…

XSS攻击实验(Elgg)

作业题目 跨站点脚本(XSS)是一种常见于web应用程序中的计算机安全漏洞。此漏洞使攻击者有可能将恶意代码(如JavaScripts)注入受害者的web浏览器。 为了演示攻击者可以做什么,我们在预先构建的Ubuntu VM映像中设置了一个名为Elgg的web应用程序。我们已经注释掉了Elgg的一些…

USB E-Maker用途

E-Marker 是“Electronically Marked Cable”的缩写,是封装在 USB-C端口中的芯片。通过这个芯片,可以得到电缆的各种参数,包括功率、数据、视频传输、ID等信息。由于 Type-C 设备之间的功能差异很大,因此在决策过程中考虑电缆至关重要。例如,如果源和接收设备都需要 100W …