Base64原理与实现
Base64编码说明
Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。 如果剩下的字符不足3个字节,则用0填充,输出字符使用'=',因此编码后输出的文本末尾可能会出现1或2个'='。
为了保证所输出的编码位可读字符,Base64制定了一个编码表,以便进行统一转换。编码表的大小为2^6=64,这也是Base64名称的由来。
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");
}
运行结果:

Base64原理与实现的更多相关文章
- Base64原理
一.Base64编码由来 为什么会有Base64编码呢?因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就 不能通过邮件传送.这样用途就受到了很大的 ...
- Base64原理解析
一. Base64编码由来 为什么会有Base64编码呢?因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就 不能通过邮件传送.这样用途就受到了很大 ...
- Base64原理解析与使用
一.Base64编码由来 为什么会有Base64编码呢?因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就 不能通过邮件传送.这样用途就受到了很大的 ...
- 一份简明的 Base64 原理解析
书接上回,在 记一个 Base64 有关的 Bug 一文里,我们说到了 Base64 的编解码器有不同实现,交叉使用它们可能引发的问题等等. 这一回,我们来对 Base64 这一常用编解码技术的原理一 ...
- base64原理,使用场景
Base64编码,是我们程序开发中经常使用到的编码方法.它是一种基于用64个可打印字符来表示二进制数据的表示方法.它通常用作存储.传输一些二进制数据编码方法!也是MIME(多用途互联网邮件扩展,主要用 ...
- Base64原理简介
Base64是一种编码方式,通常用于将二进制数据转换成可见字符的形式,该过程可逆. 过程大致如下: 1. 对64个可见字符,进行一个索引编码.索引是二进制的值,对应找到一个可见字符. Base64 编 ...
- base64 原理
Base64编码之所以称为Base64,是因为其使用64个字符来对任意数据进行编码,同理有Base32.Base16编码.标准Base64编码使用的64个字符为: 这64个字符是各种字符编码(比如AS ...
- Base64原理 bits 3->4 8bits/byte-->6bits/byte
实践: window.btoa('a')a YQ==abcdef YWJjZGVmabc YWJjab YWI= https://en.wikipedia.org/wiki/Base64 The Ba ...
- php base64 原理
#include <stdio.h> #include <stdlib.h> #include <string.h> static const char base6 ...
随机推荐
- 格式化p6spy的输出日志
众所周知, p6spy打印出来的日志是一行很长很长的内容, 很不容易查看, 牛B的p6spy为什么就不能想hibernate那样有format_sql的功能? 竟然没有, 我只好自己动手写一个日志输出 ...
- FireDAC 下的 Sqlite [8] - 自定义函数
Sqlite 本身没有这个功能, FireDAC 通过 TFDSQLiteFunction 增加了该功能; 尽管通过某些 SQL 语句或通过视图也可以达到类似效果, 但函数会更灵活些. 本例先建了一个 ...
- TCP状态知识总结(图解)
tcp状态: LISTEN:侦听来自远方的TCP端口的连接请求 SYN-SENT:再发送连接请求后等待匹配的连接请求 SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认 ...
- 使用jqprint插件完成页面打印
使用jqprint插件完成页面打印 jqprint是一个基于jQuery编写的页面打印的一个小插件,但是不得不承认这个插件确实很厉害,最近的项目中帮了我的大忙,在Web打印的方面,前端的打印基本是靠w ...
- C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\文件不断增长,如何处理?
很久没有写博了.最近半年除了忙活布置新家和过年期间走亲访友之外,都是在公司处理一些项目中的杂事:连家里买的很多书都停下来没看了,感觉这段时间在事业和学习上一直都是忙忙碌碌,却又碌碌无为. 吐槽完,说正 ...
- SourceTree的简单使用
原文网址:http://blog.csdn.net/u011439289/article/details/42126507 今天开始参与公司项目的代码编写,公司内部采用的是gitlib,所以用到了So ...
- Asp.net core使用IIS在windows上进行托管
摘要 最近项目中,尝试使用asp.net core开发,在部署的时候,考虑现有硬件,只能部署在windows上,linux服务器暂时没有. 部署注意事项 代码中启用iis和Kestrel public ...
- 将 tomcat 安装成 windows 服务
1.下载 tomcat 的windows 压缩包,一般以 .zip ,而且文件名中有 bin 的文件就是 2.解压下载的文件到某一个目录下,eg: TOMCAT_HOME 3.打开 cmd ,运行 % ...
- SQLUnit 环境搭建
1 技术须要积累 前几天去一位笛友小赖家玩,才知道他的笛子吹得好不是偶然.是由于他真的用功了,电脑里面下载有超多的视频.教程等!这真的非常让我震撼!一直是在公司做技术,但资料考不出来,而我整理了多少技 ...
- 用开源项目circular progress button实现有进度条的Button
circular progress button可以让button实现进度条,效果和动画都做的很赞,只是有点小bug.需要注意的是按钮上的文字不能太大,否则会出现错位. 项目的地址:https://g ...