Base64原理与实现
2024-09-29 18:26:05
Base64编码说明
Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。 如果剩下的字符不足3个字节,则用0填充,输出字符使用'=',因此编码后输出的文本末尾可能会出现1或2个'='。
为了保证所输出的编码位可读字符,Base64制定了一个编码表,以便进行统一转换。编码表的大小为2^6=64,这也是Base64名称的由来。
转码过程举例:
3*8=4*6
内存1个字符占8位
转前: s 1 3
先转成ascii:对应 115 49 51
2进制: 01110011 00110001 00110011
6个一组(4组) 011100110011000100110011
然后才有后面的 011100 110011 000100 110011
然后计算机是8位8位的存数 6不够,自动就补两个高位0了
所有有了 高位补0
科学计算器输入 00011100 00110011 00000100 00110011
得到 28 51 4 51
查对下照表 c z E z
Base64编码表
码值 | 字符 | 码值 | 字符 | 码值 | 字符 | 码值 | 字符 | |||
---|---|---|---|---|---|---|---|---|---|---|
0 | A | 16 | Q | 32 | g | 48 | w | |||
1 | B | 17 | R | 33 | h | 49 | x | |||
2 | C | 18 | S | 34 | i | 50 | y | |||
3 | D | 19 | T | 35 | j | 51 | z | |||
4 | E | 20 | U | 36 | k | 52 | 0 | |||
5 | F | 21 | V | 37 | l | 53 | 1 | |||
6 | G | 22 | W | 38 | m | 54 | 2 | |||
7 | H | 23 | X | 39 | n | 55 | 3 | |||
8 | I | 24 | Y | 40 | o | 56 | 4 | |||
9 | J | 25 | Z | 41 | p | 57 | 5 | |||
10 | K | 26 | a | 42 | q | 58 | 6 | |||
11 | L | 27 | b | 43 | r | 59 | 7 | |||
12 | M | 28 | c | 44 | s | 60 | 8 | |||
13 | N | 29 | d | 45 | t | 61 | 9 | |||
14 | O | 30 | e | 46 | u | 62 | + | |||
15 | P | 31 | f | 47 | v | 63 | / |
C++实现:
base64.h
#ifndef _BASE64_HH
#define _BASE64_HH #ifdef __cplusplus
extern "C" {
#endif //__cplusplus unsigned char* base64Decode(char* pszInput, unsigned int& iReturnSize, bool trimTrailingZeros = true); char* base64Encode(char const* origSigned, unsigned iOrigLength); #ifdef __cplusplus
}
#endif //__cplusplus #endif //_BASE64_HH
base64.cpp
#include "base64.h"
#include <string.h> static char base64DecodeTable[];
//初始化编码对照表
static const char base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char* strDupSize(char const* str)
{
if (str == NULL) return NULL;
size_t len = strlen(str) + ;
char* copy = new char[len]; return copy;
} //初始化解码对照表
static void initBase64DecodeTable()
{
for (int i = ; i < ; ++i)
base64DecodeTable[i] = (char)0x80; // default value: invalid for (int i = 'A'; i <= 'Z'; ++i)
base64DecodeTable[i] = + (i - 'A');
for (int i = 'a'; i <= 'z'; ++i)
base64DecodeTable[i] = + (i - 'a');
for (int i = ''; i <= ''; ++i)
base64DecodeTable[i] = + (i - '');
base64DecodeTable[(unsigned char)'+'] = ;
base64DecodeTable[(unsigned char)'/'] = ;
base64DecodeTable[(unsigned char)'='] = ; //0x40
} // 解码
unsigned char* base64Decode(char* pszInput, unsigned int& iReturnSize, bool trimTrailingZeros)
{
static bool haveInitedBase64DecodeTable = false;
if (!haveInitedBase64DecodeTable)
{
initBase64DecodeTable();
haveInitedBase64DecodeTable = true;
} unsigned char* pszOutput = new unsigned char[strlen(pszInput)];
int k = ;
/*******************************************************************************************
*技巧:先减去3 ---in case "pszInput" is not a multiple of 4 bytes (although it should be) *
* 个人觉得这里不用做处理,因为编码时候已经做过处理,密文肯定为4的整数倍 *
*******************************************************************************************/
int const jMax = strlen(pszInput) - ; //将密文四个字节为一组,每组解码为三个字节
for (int j = ; j < jMax; j += )
{
char inTmp[], outTmp[];
for (int i = ; i < ; ++i)
{
inTmp[i] = pszInput[i+j];
outTmp[i] = base64DecodeTable[(unsigned char)inTmp[i]];
if ((outTmp[i]&0x40) != ) //如果遇到'=',将其视为结束字符
outTmp[i] = 0x00;
} pszOutput[k++] = (outTmp[]<<) | (outTmp[]>>);
pszOutput[k++] = (outTmp[]<<) | (outTmp[]>>);
pszOutput[k++] = (outTmp[]<<) | outTmp[];
} if (trimTrailingZeros)
{
while (k > && pszOutput[k-] == '\')
--k;
}
iReturnSize = k;
unsigned char* result = new unsigned char[iReturnSize];
memset(result, , iReturnSize);
memmove(result, pszOutput, iReturnSize);
delete[] pszOutput;
return result;
} // 编码
char* base64Encode(char const* origSigned, unsigned iOrigLength)
{
unsigned char const* orig = (unsigned char const*)origSigned;
if (orig == NULL)
return NULL; unsigned const iNumResultBytes = *(iOrigLength/ + (iOrigLength% ? : ));
char* result = new char[iNumResultBytes + ]; //源码三个字节为一组,编码后将三个字节变为四个字节
unsigned i;
for (i = ; i < iOrigLength/; ++i)
{
// 取源码的第一个字节的前六位,前面加两个零生成第一个字节
result[*i+] = base64Char[(orig[*i]>>) & 0x3F];
// 取源码的第一个字节的后两位和第二个字节的前四位,前面补两个零生成第二个字节
result[*i+] = base64Char[((orig[*i]<<) | (orig[*i+]>>)) & 0x3F];
// 取源码的第二个字节的后四位和第三个字节的前两位,前面补两个零生成第三个字节
result[*i+] = base64Char[((orig[*i+]<<) | (orig[*i+]>>)) & 0x3F];
// 取源码的第三个字节的后六位,前面补两个零生成第四个字节
result[*i+] = base64Char[orig[*i+]&0x3F];
}
//不足三个字节的最后补'='字符,补足三个字节
if (iOrigLength%)
{
result[*i+] = base64Char[(orig[*i]>>) & 0x3F];
if (iOrigLength% == )
{
result[*i+] = base64Char[((orig[*i]<<) | (orig[*i+]>>))&0x3F];
result[*i+] = base64Char[(orig[*i+]<<)&0x3C];
}
else
{
result[*i+] = base64Char[((orig[*i])<<)&0x3F];
result[*i+] = '=';
}
result[*i+] = '=';
} result[iNumResultBytes] = '\0';
return result;
}
测试代码main.cpp
#include "base64.h"
#include <iostream> using namespace std; int main()
{
cout << "请输入要转换的字符串(支持中文):" << endl;
char szStrOrigin[];
scanf("%s", szStrOrigin);
unsigned int iReturnSize;
cout << "编码之前字符串:" << szStrOrigin << endl;
char *pEncodeStr = base64Encode(szStrOrigin, strlen(szStrOrigin));
cout << "编码之后字符串:" << pEncodeStr << endl;
unsigned char *pDecodeStr = base64Decode(pEncodeStr, iReturnSize);
cout << "解码之后字符串:" << pDecodeStr << endl;
system("pause");
}
运行结果:
最新文章
- 【菜鸟学习jquery源码】数据缓存与data()
- 普林斯顿结构 VS 哈佛结构
- php两种导出excel的方法
- python中的多继承
- [百度空间] [原] Empty base class optimization
- DataGridView之行的展开与收缩
- 设计的SOA架构
- [XJOI NOI2015模拟题13] C 白黑树 【线段树合并】
- validate方法配置项
- Adt 配置注释模板
- node.js(八) 有趣的东西才开始哦
- Android项目实战手机安全卫士(02)
- NET开发面向对象2
- Dynamics CRM 警惕Odata查询的陷阱
- 阿里巴巴Java开发规约插件
- Spring拓展接口之FactoryBean,我们来看看其源码实现
- python全栈开发 * 31知识点汇总 * 180716
- 双列集合Map
- 关于elment-ui树形控件Tree的使用
- Vue组件中引入jQuery
热门文章
- POJ.1379.Run Away(模拟退火)
- Beta冲刺准备
- j.u.c系列(05)---之重入锁:ReentrantLock
- Azure虚机磁盘容量警报(邮件提醒)
- asp.net MVC 中 Session统一验证的方法
- 《Go语言实战》摘录:7.1 并发模式 - runner
- delphi DockPresident
- The .NET weak event pattern in C#
- Spring Cloud Gateway服务网关
- 检查radio/checkbox是否至少选择一项