selph
selph
发布于 2021-10-28 / 681 阅读
0
0

Base64编码原理&代码实现

Base64编码原理

首先,Base64编码有什么用呢?

  1. 传输:用于将二进制数据编码成文本数据进行传输,比如图片的传输等...
  2. 加密:通过修改索引表进行编码,没有索引表就很难解码
  3. 还有啥用我就不知道了

其次,Base64编码是怎么一回事?

Base64一句话概括:就是把二进制数据按位切割形成索引,通过索引映射到索引表中的可见字符,用这个可见字符来代替二进制数据传输

因为一个字节的二进制数据有8位,数据范围是0~255,可见字符比这少多了,不能直接用这8位数据来索引可见字符

所以需要进行切割,拿出一部分位来进行当索引,根据ASCII码表,可见字符数量有26个大写字母+26个小写字母+10个数字+27个符号 = 89个:

查看源图像

直接用二进制位来当索引的话,需要取2的倍数个字符来当索引表,最大能取到2的6次方,也就是64个字符来作为索引表,索引需要6个二进制位(所以编码叫Base64,同理也有Base32,Base16等),通常默认使用的Base64索引表是这样的:

img

于是需要把二进制数据以6位一划分,每6位获得一个索引号,根据索引号来转换可见字符,如下图所示,这里的二进制数据是字符串,每个字符都6位一分,得到索引号,使用索引号对应索引表得到一个可见字符,组成Base64编码

img

每3个字节,就能获得4个索引号,当不满3个字节时,有两种情况如下图所示,当索引号6位没有完整填充时,则会在索引号6位的空位填充0,如果索引位6位全是空的,则直接使用=字符(填充字符)代替索引获取字符

img

图来自:base64加密原理详解_小白-CSDN博客_base64加密

原理部分介绍到此结束,接下来代码实现一下

Base64编码代码实现

代码比较简单,所以也没啥注释,要注意一下,这里的关键点在于位运算(对位的切割与拼接)

测试环境:

  • Windows 10 21H1
  • Visual Studio 2019

Base64.h

#pragma once
#include <iostream>
#include <string>

class Base64calc
{
public:
	Base64calc();
	Base64calc(char * newIndexTable,char newEntrychar = '=');
	~Base64calc();

public:
	void printIndexTable();
	char getIndex(char encodeChar);
	std::string encodeBase64(char* unencodeStr);
	std::string decodeBase64(char* encodeStr);
private:
	char indexTable[64];	// 索引表,需要64位,支持通过字符数组设定
	char entryChar;		// 空白填充符
};

Base64.cpp

#include "Base64.h"

Base64calc::Base64calc()
{
	// 生成默认索引表
	for (int i = 0; i < 64;i++ ) {
		if (i <= 25) {
			indexTable[i] = 'A' + i;
		}
		else if (i > 25 && i <= 51) {
			indexTable[i] = 'a' + i - 26;
		}
		else if(i>51 && i<=61){
			indexTable[i] = '0' + i - 52;
		}
		else {
			if (i == 62) {
				indexTable[i] = '+';
			}
			if (i == 63) {
				indexTable[i] = '/';
			}
		}
	}
	entryChar = '=';
}


Base64calc::Base64calc(char* newIndexTable, char newEntrychar)
{
	memcpy(indexTable, newIndexTable, 64);
	entryChar = newEntrychar;
}

Base64calc::~Base64calc()
{

}

void Base64calc::printIndexTable()
{
	if (indexTable != NULL) {
		printf("IndexTable: ");
		for (int i = 0; i < 64; i++)
		{
			std::cout << indexTable[i];
		}
		std::cout << std::endl;
	}
}

char Base64calc::getIndex(char encodeChar)
{
	for (char i = 0; i < 64; i++)
	{
		if (encodeChar == indexTable[i])return i;
	}
	return -1;
}


std::string Base64calc::encodeBase64(char* unencodeStr)
{
	std::string retStr;
	int strLength = strlen(unencodeStr);
	
	// 计算能完整转换的字节部分
	for (int i = 0; i < strLength - strLength % 3; i += 3) {
		char byte1 = unencodeStr[i];
		char byte2 = unencodeStr[i+1];
		char byte3 = unencodeStr[i+2];

		retStr += indexTable[byte1 >> 2];
		retStr += indexTable[byte2 >> 4 | (byte1 & 0x03) << 4];
		retStr += indexTable[byte3 >> 6 | (byte2 & 0x0F) << 2];
		retStr += indexTable[byte3 & 0x3F];
	}

	// 缺2字节时
	if (strLength % 3 == 1) {
		char byte = unencodeStr[strLength - 1];

		retStr += indexTable[byte >> 2];
		retStr += indexTable[(byte & 0x03) << 4];
		retStr += entryChar;
		retStr += entryChar;
	}

	// 缺1字节时
	if (strLength % 3 == 2) {
		char byte1 = unencodeStr[strLength - 2];
		char byte2 = unencodeStr[strLength - 1];

		retStr += indexTable[byte1 >> 2];
		retStr += indexTable[byte2 >> 4 | (byte1 & 0x03) << 4];
		retStr += indexTable[(byte2 & 0x0F) << 2];
		retStr += entryChar;
	}
	return retStr;
}

std::string Base64calc::decodeBase64(char* encodeStr)
{
	std::string retStr;
	int strLength = strlen(encodeStr);

	// 计算能完整转换的字节部分
	for (int i = 0; i < strLength; i += 4) {
		char byte1 = encodeStr[i];
		char byte2 = encodeStr[i + 1];
		char byte3 = encodeStr[i + 2];
		char byte4 = encodeStr[i + 3];

		retStr += (char)(getIndex(byte1) << 2) | (getIndex(byte2) >> 4);
		if (byte3 != '=')
			retStr += (getIndex(byte2) << 4) | (getIndex(byte3) >> 2);
		if (byte4 != '=')
			retStr += (getIndex(byte3) << 6) | (getIndex(byte4));
	}
	return retStr;
}

entry.cpp 测试代码

#include "Base64.h"
#include <iostream>
#include <string>

int main() {
	std::string str = "Hello selph";
	std::cout << "oriStr:" << str << std::endl;
	std::cout << std::endl;

	// 标准Base64索引表编码解码
	Base64calc test;
	test.printIndexTable();
	std::string encode = test.encodeBase64((char*)str.data());
	std::string decode = test.decodeBase64((char*)encode.data());
	std::cout << "encode:" << encode << std::endl;
	std::cout << "decode:" << decode << std::endl;

	std::cout << std::endl;

	// 自定义Base64索引表编码解码
	char* myIndexTable =(char*) "abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ<>";
	Base64calc testCostom(myIndexTable, 'a');
	testCostom.printIndexTable();
	std::string encode1 = testCostom.encodeBase64((char*)str.data());
	std::string decode1 = testCostom.decodeBase64((char*)encode1.data());
	std::cout << "encode:" << encode1 << std::endl;
	std::cout << "decode:" << decode1 << std::endl;
	return 0;
}

测试截图

image-20211028134638665


评论