首页 > 其他分享 >Base64编码原理

Base64编码原理

时间:2024-10-30 17:09:17浏览次数:1  
标签:编码 string Base64 ret char len 原理 data

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 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

14 O  31 f   48 w   

15 P  32 g   49 x

16 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 = string
        for 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_convert

    def fillIt(self, string, factor, item):
        """
        指定倍数填充指定字符
        string:原字符串
        factor:倍数
        item:填充字符
        """
        length = len(string)
        remainder = length % factor
        if remainder:
            times = factor - remainder
            string = string + times * item
        return string

    def 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 % bits
        if remain != 0:
            new_list.append(string[-remain:])
        return new_list


if __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_H

const 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博客

标签:编码,string,Base64,ret,char,len,原理,data
From: https://www.cnblogs.com/hnu-hua/p/18516202

相关文章

  • Ansible原理和安装
    一.概念简介Ansible是一个IT自动化工具。它能配置系统、部署软件、编排更复杂的IT任务,如连续部署或零停机时间滚动更新。连接其他主机(管理节点)默认使用ssh协议特性Agentless:不需要在被管理节点上安装客户端,只要有sshd即可Serverless:在服务端不需要启动任何服务,只需要执......
  • 005 字符编码与文件处理
    知识储备1#计算机三大核心硬件:CPU,内存,硬盘23#1、软件运行之前,软件的代码及其数据都是存放在硬盘中的4#2、任何软件的启动都是将数据从硬盘读入内存,然后CPU从内存中取出指令并执行5#3、软件运行过程中产生的数据最先都是存放在内存中的,若想永久保存软件产生的数据......
  • 【GiraKoo】常用编码的对比(ASCII,GB2312,GBK,GB18030,UCS,Unicode)
    甯哥敤缂栫爜鐨勫姣旓紙ASCII锛孏B2312锛孏BK锛孏B18030锛孶CS锛孶nicode锛�鍦ㄧ▼搴忓紑鍙戜腑锛屾枃瀛楃紪鐮佷竴鐩存壆婕旂潃浜虹暅鏃犲锛屽嵈鑳屽悗鎹呬竴鍒€鐨勮鑹层€�鍙兘鍦ㄦ簮浠g爜鏂囦欢涓紝娉ㄩ噴鑾悕鍏跺鍦板彉鎴愪簡涔辩爜銆�鍙兘鏄彂閫佺粰鍒......
  • 算法网关视频分析网关算法定制:适合视频分析的深度学习架构及视频分析原理和应用
    随着信息技术的突飞猛进,视频监控技术已经从模拟监控时代跨入了高清、智能化的新纪元。在这场技术革新中,算法定制视频分析网关扮演着至关重要的角色,它作为连接前端摄像头与后端管理平台的桥梁,其作用日益凸显,不可或缺。一、适合视频分析的深度学习架构深度学习在视频监控系统中的......
  • 安全帽检测视频分析网关算法定制安全帽检测算法的原理及应用
    安全帽在建筑和制造业等企业的生产活动中扮演着至关重要的劳动保护角色,其佩戴情况的实时监控是企业安全生产管理的关键组成部分。以往依赖人工巡检的安全监管方式不仅效率低,而且难以实现全面监督。应用安全帽检测视频分析网关,安全监管已经从被动式监察转变为主动式监控,利用技术手......
  • 独热编码(One-Hot Encoding)
    一、独热编码出现之前:针对无序离散的分类特征,机器学习算法的分类器并不能直接进行数据处理。因为,分类器通常处理的数据是连续且有序的。但是我们可以对这些离散的特征数据建立映射表来让其有序并且连续起来。例如:针对一个人对象,我们可以假设其属性进行了如下映射。性别特征:["男"......
  • QwaitCondition.的工作原理
    背景:之前只知道个QWaitCondition用于同步不同的线程运行状态。但不知道为何这样做。为什么还要在QWaitcondition.wai()中还要传入一个QMutext变量的指针。QWaitCondition.wait的工作原理:QWaitCondition.wait的工作原理:伪代码Qmutexmutex;QwaitConditioncon......
  • USB协议详解第28讲(USB硬件设计和热拔插原理)
    1.USB引脚接线定义对于四线制的USB,即USB1.0、USB1.1和USB2.0,USB硬件接口有4根接线,如下图。引脚名称电缆颜色描述1VBUSRed+5V,电源2D−WhiteData−,数据线3D+GreenData+,数据线4GNDBlackGround,接地2.低速USB设备硬件设计原理低速设备端在*D......
  • 计算机网络(Ⅵ)应用层原理
    一些网络应用的例子:E-mail     Internaet电话Web      电子支付文本信息   搜索P2P文件共享流媒体即时通讯   实时电视会议........ 创建一个网络应用:1.编程2.在不同的端系统上运行。网络应用的体系架构可能的应用架构1.......
  • 【数据结构】哈夫曼树的构建和哈夫曼编码
    说明本篇为笔者学习随记,供学习和复习使用结构体定义typedefstruct{ intweight=0; intparent=0,lchild=0,rchild=0;}HTNode;此处=0可使结构体在构建时就自动初始化typedefchar**HuffmanCode;把多重指针换成HuffmanCode 哈夫曼树的构建构建思路:a)初始化哈夫......