目录

  • 一、前言
  • 二、代码实现
  • 附:源代码下载

一、前言

  Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2049,上面有MIME的详细规范。
  Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3 * 8 = 4 * 6 = 24),然后把6Bit再添加两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
  Base64的编码转换表。

  下面简单介绍一下编码的原理:

转换前:
   字符串 - hello
   二进制 - 01101000,01100101,01101100,01101100,01101111
转换后:
   二进制 - 00011010,00000110,00010101,00101100,00011011,00000110,00111100
   对应码表中的值 - a,G,V,s,b,G,8
   编码后的字符串 - aGVsbG8=
注意:
  8Bit字节转换为6Bit字节,如果剩余的不足6Bit,则在低位补0,直到满足6Bit,最后才在高位补两个0。


  Base64编码都是以3个字节作为基本单位进行转换,编码转换后的数据都是4的倍数,如果源数据大小不是3的倍数,则会在编码转换后的数据末尾增加一个或两个“=”(最多两个),保证编码输出的数据大小为4的倍数。

二、代码实现

  头文件 base64.h

/************************************************************************ File name    : base64.h* Function     : base64 encoding and decoding of data or file.* Created time : 2020-08-04**********************************************************************/#ifndef BASE64_H
#define BASE64_H//base64编码
int base64_encode(const char *indata, int inlen, char *outdata, int *outlen);
//base64解码
int base64_decode(const char *indata, int inlen, char *outdata, int *outlen);
//base64编码文件
int base64_encode_file(const char *src, const char *dst);
//base64解码文件
int base64_decode_file(const char *src, const char *dst);#endif // BASE64_H

  源文件 base64.c

/************************************************************************ File name    : base64.cpp / base64.c* Function     : base64 encoding and decoding of data or file.* Created time : 2020-08-04**********************************************************************/#include <stdio.h>
#include <string.h>//base64 编码转换表,共64个
static const char base64_encode_table[] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
};//base64 解码表
static const unsigned char base64_decode_table[] = {//每行16个0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                //1 - 160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                //17 - 320,0,0,0,0,0,0,0,0,0,0,62,0,0,0,63,              //33 - 4852,53,54,55,56,57,58,59,60,61,0,0,0,0,0,0,      //49 - 640,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,           //65 - 8015,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,     //81 - 960,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, //97 - 11241,42,43,44,45,46,47,48,49,50,51,0,0,0,0,0      //113 - 128
};/*** @brief base64_encode     base64编码* @param indata            需编码的数据* @param inlen             需编码的数据大小* @param outdata           编码后输出的数据* @param outlen            编码后输出的数据大小* @return  int             0:成功    -1:无效参数*/
int base64_encode(const char *indata, int inlen, char *outdata, int *outlen)
{if(indata == NULL || inlen <= 0) {return -1;}
/*//方法一:int i, j;char ch;int add_len = (inlen % 3 == 0 ? 0 : 3 - inlen % 3); //原字符串需补齐的字符个数int in_len = inlen + add_len; //源字符串补齐字符后的长度,为3的倍数if(outdata != NULL) {//编码,长度为调整之后的长度,3字节一组for(i=0, j=0; i<in_len; i+=3, j+=4) {//将indata第一个字符向右移动2bit(丢弃2bit)ch = base64_encode_table[(unsigned char)indata[i] >> 2]; //对应base64转换表的字符outdata[j] = ch; //赋值//处理最后一组(最后3个字节)的数据if(i == in_len - 3 && add_len != 0) {if(add_len == 1) {outdata[j + 1] = base64_encode_table[(((unsigned char)indata[i] & 0x03) << 4) | ((unsigned char)indata[i + 1] >> 4)];outdata[j + 2] = base64_encode_table[((unsigned char)indata[i + 1] & 0x0f) << 2];outdata[j + 3] = '=';}else if(add_len == 2) {outdata[j + 1] = base64_encode_table[((unsigned char)indata[i] & 0x03) << 4];outdata[j + 2] = '=';outdata[j + 3] = '=';}}//处理正常的3字节数据else {outdata[j + 1] = base64_encode_table[(((unsigned char)indata[i] & 0x03) << 4) | ((unsigned char)indata[i + 1] >> 4)];outdata[j + 2] = base64_encode_table[(((unsigned char)indata[i + 1] & 0x0f) << 2) | ((unsigned char)indata[i + 2] >> 6)];outdata[j + 3] = base64_encode_table[(unsigned char)indata[i + 2] & 0x3f];}}}if(outlen != NULL) {*outlen = in_len * 4 / 3; //编码后的长度}
*///方法二:int i, j;unsigned char num = inlen % 3;if(outdata != NULL) {//编码,3个字节一组,若数据总长度不是3的倍数,则跳过最后的 num 个字节数据for(i=0, j=0; i<inlen - num; i+=3, j+=4) {outdata[j] = base64_encode_table[(unsigned char)indata[i] >> 2];outdata[j + 1] = base64_encode_table[(((unsigned char)indata[i] & 0x03) << 4) | ((unsigned char)indata[i + 1] >> 4)];outdata[j + 2] = base64_encode_table[(((unsigned char)indata[i + 1] & 0x0f) << 2) | ((unsigned char)indata[i + 2] >> 6)];outdata[j + 3] = base64_encode_table[(unsigned char)indata[i + 2] & 0x3f];}//继续处理最后的 num 个字节的数据if(num == 1) { //余数为1,需补齐两个字节'='outdata[j] = base64_encode_table[(unsigned char)indata[inlen - 1] >> 2];outdata[j + 1] = base64_encode_table[((unsigned char)indata[inlen - 1] & 0x03) << 4];outdata[j + 2] = '=';outdata[j + 3] = '=';}else if(num == 2) { //余数为2,需补齐一个字节'='outdata[j] = base64_encode_table[(unsigned char)indata[inlen - 2] >> 2];outdata[j + 1] = base64_encode_table[(((unsigned char)indata[inlen - 2] & 0x03) << 4) | ((unsigned char)indata[inlen - 1] >> 4)];outdata[j + 2] = base64_encode_table[((unsigned char)indata[inlen - 1] & 0x0f) << 2];outdata[j + 3] = '=';}}if(outlen != NULL) {*outlen = (inlen + (num == 0 ? 0 : 3 - num)) * 4 / 3; //编码后的长度}return 0;
}/*** @brief base64_decode     base64解码* @param indata            需解码的数据* @param inlen             需解码的数据大小* @param outdata           解码后输出的数据* @param outlen            解码后输出的数据大小* @return  int             0:成功    -1:无效参数* 注意:解码的数据的大小必须大于4,且是4的倍数*/
int base64_decode(const char *indata, int inlen, char *outdata, int *outlen)
{if(indata == NULL || inlen <= 0 || (outdata == NULL && outlen == NULL)) {return -1;}if(inlen < 4 ||inlen % 4 != 0) { //需要解码的数据长度不是4的倍数  //inlen < 4 ||return -1;}int i, j;//计算解码后的字符串长度int len = inlen / 4 * 3;if(indata[inlen - 1] == '=') {len--;}if(indata[inlen - 2] == '=') {len--;}if(outdata != NULL) {for(i=0, j=0; i<inlen; i+=4, j+=3) {outdata[j] = (base64_decode_table[(unsigned char)indata[i]] << 2) | (base64_decode_table[(unsigned char)indata[i + 1]] >> 4);outdata[j + 1] = (base64_decode_table[(unsigned char)indata[i + 1]] << 4) | (base64_decode_table[(unsigned char)indata[i + 2]] >> 2);outdata[j + 2] = (base64_decode_table[(unsigned char)indata[i + 2]] << 6) | (base64_decode_table[(unsigned char)indata[i + 3]]);}}if(outlen != NULL) {*outlen = len;}return 0;
}/*** @brief base64_encode_file    base64编码文件* @param src                   需编码的文件路径* @param dst                   编码后输出的文件路径* @return  int                 0:成功    -1:无效参数     -2:文件操作失败*/
int base64_encode_file(const char *src, const char *dst)
{if(src == NULL || dst == NULL) {return -1;}FILE *src_fp, *dst_fp;char rdata[128*3+3]; //存放读取到的文件数据,+3表示预留3个字节空间存放余下来的数据size_t rmemb; //读文件数据返回值,读取到的块数size_t nmemb = sizeof(rdata) - 3; //每次读取文件数据的块数,最好是3的倍数char encode_data[(nmemb+(nmemb%3==0?0:3-nmemb%3))*4/3+1]; //存放编码后的数据int encode_datalen; //编码后的数据大小unsigned char num = 0, lastnum = 0;src_fp = fopen(src, "rb");if(NULL == src_fp) {perror("open src file failed");return -2;}dst_fp = fopen(dst, "wb");if(NULL == dst_fp) {fclose(src_fp);perror("open dst file failed");return -2;}while(1) {//memset(rdata, 0, sizeof(rdata));//memset(encode_data, 0, sizeof(encode_data));encode_datalen = 0;rmemb = fread(rdata + lastnum, 1, nmemb, src_fp);if((lastnum + rmemb) % 3 == 0 || rmemb < nmemb) { //读取到的数据与上次余下来的数据总大小是3的倍数 或 文件已读完(或出错)base64_encode(rdata, lastnum + rmemb, encode_data, &encode_datalen);fwrite(encode_data, 1, encode_datalen, dst_fp);lastnum = 0;}else {num = (lastnum + rmemb) % 3; //余下来的字节数base64_encode(rdata, lastnum + rmemb - num, encode_data, &encode_datalen);fwrite(encode_data, 1, encode_datalen, dst_fp);//将余下来的数据移动至缓冲区最前面if(num == 1) {rdata[0] = rdata[lastnum + rmemb - 1];}else if(num == 2) {rdata[0] = rdata[lastnum + rmemb - 2];rdata[1] = rdata[lastnum + rmemb - 1];}lastnum = num;}if(rmemb < nmemb) { //文件已读完 或 出错break;}}fclose(src_fp);fclose(dst_fp);return 0;
}/*** @brief base64_decode_file    base64解码文件* @param src                   需解码的文件路径* @param dst                   解码后输出的文件路径* @return  int                 0:成功    -1:无效参数     -2:文件操作失败*/
int base64_decode_file(const char *src, const char *dst)
{if(src == NULL || dst == NULL) {return -1;}FILE *src_fp, *dst_fp;char rdata[128*4]; //存放读取到的文件数据size_t rmemb; //读文件数据返回值,读取到的块数size_t nmemb = sizeof(rdata); //每次读取文件数据的块数,最好是4的倍数char decode_data[nmemb/4*3+1]; //存放解码后的数据,大小计算int decode_datalen; //解码后的数据大小unsigned char num = 0, lastnum = 0;src_fp = fopen(src, "rb");if(NULL == src_fp) {perror("open src file failed");return -2;}dst_fp = fopen(dst, "wb");if(NULL == dst_fp) {fclose(src_fp);perror("open dst file failed");return -2;}while(1) {//memset(rdata, 0, sizeof(rdata));//memset(encode_data, 0, sizeof(encode_data));decode_datalen = 0;rmemb = fread(rdata + lastnum, 1, nmemb, src_fp);if((lastnum + rmemb) % 4 == 0 || rmemb < nmemb) { //读取到的数据与上次余下来的数据总大小是4的倍数 或 文件已读完(或出错)base64_decode(rdata, lastnum + rmemb, decode_data, &decode_datalen);fwrite(decode_data, 1, decode_datalen, dst_fp);lastnum = 0;}else {num = (lastnum + rmemb) % 4; //余下来的字节数base64_decode(rdata, lastnum + rmemb - num, decode_data, &decode_datalen);fwrite(decode_data, 1, decode_datalen, dst_fp);//将余下来的数据移动至缓冲区最前面if(num == 1) {rdata[0] = rdata[lastnum + rmemb - 1];}else if(num == 2) {rdata[0] = rdata[lastnum + rmemb - 2];rdata[1] = rdata[lastnum + rmemb - 1];}else if(num == 3) {rdata[0] = rdata[lastnum + rmemb - 3];rdata[1] = rdata[lastnum + rmemb - 2];rdata[2] = rdata[lastnum + rmemb - 1];}lastnum = num;}if(rmemb < nmemb) { //文件已读完 或 出错break;}}fclose(src_fp);fclose(dst_fp);return 0;
}

附:源代码下载

C语言实现Base64编解码(加密和解密).zip

C语言实现Base64编解码(加密和解密)相关推荐

  1. Jva编解码,加密工具类大全(Base64编解码,URL 编解码,sha56_Hmac加密,MD5对字符串进行加密,java自带类实现SHA-256方式加密)

    Base64编解码 /*** Base64编码.*/public static String encodeBase64(byte[] input) {return new String(Base64. ...

  2. 【cue语言系列学习】base64编解码

    [cue语言系列学习]base64编解码 release author: ningan123 release time: 2022-08-14 在线运行 工具 三种不同的输出方式,输出的结果是不一样的 ...

  3. Java 原生 Base64 编解码、Md5、SHA-1、SHA-256 加密摘要算法

    目录 常用加密算法对比 Base64 编解码 MessageDigest 信息摘要 MD5 信息摘要算法 常用加密算法对比 常用加密算法对比 Base64 编解码 1.BASE64 有自己的编码表,可 ...

  4. Java对base64编解码总结

    概述 java对base64编解码的通用处理方法. 关于base64编码Encode和Decode编码的几种方式 Base64是一种能将任意Binary资料用64种字元组合成字串的方法,而这个Bina ...

  5. Java实现BASE64编解码

    Java实现BASE64编解码 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs BASE64和其它类似的编码算法通经常使用于转换二进制数据为文本数据,其目 ...

  6. Python学习教程:Python3内置模块之base64编解码方法小结

    Python学习教程:Python3内置模块之base64编解码方法小结 概述 Base64 是网络上最常见的用于传输 8Bit 字节码的编码方式之一,Base64 就是一种基于 64 个可打印字符来 ...

  7. MSDK手Q邀请透传参数问题:url编解码与base64编解码

    最近做MSDK手Q的邀请功能,遇到一个坑,手Q结构化消息分享功能接口如下: /*** @param scene 标识发送手Q会话或者Qzone* eQQScene.QQScene_QZone: 分享到 ...

  8. Base64编解码原理并用Java手工实现Base64编解码

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

  9. base64编码 vba_【VBA研究】如何用Base64 编解码方法实现简单的加解密

    Base64编码的思想是是采用64个基本的ASCII码字符对数据进行重新编码,将数据变成字符串实现文本传输.由于编码简单,所以很容易实现,代码也是现成的.利用这个编码规则可以实现简单的加解密.编解码方 ...

  10. golang:base64编解码(转)

    转自:golang:base64编解码 Go 语言的标准库自带了 Base64 编码算法,通过几行代码就可以对数据进行编码 编解码字符串 package main import ("enco ...

最新文章

  1. UVA1626 括号序列 Brackets sequence(区间DP匹配括号,输出匹配方案)
  2. python遍历数组冒泡排序_经典排序算法(冒泡排序,选择排序,插入排序,快速排序,堆排序)python实现...
  3. Linux计划任务(at,crontab)
  4. Mysql报错130_mysql 突然报错,连接不上
  5. 【操作系统】常见进程调度算法特点总结比较
  6. 网易云音乐评论催泪刷屏?我用Python抓取了1008328条热评告诉你为什么!
  7. 【转】C++从零实现神经网络
  8. Fabric1.4源码解析:Peer节点启动过程
  9. kettle-查询控件
  10. GlideDemo【Glide3.7.0版本的简单使用以及圆角功能】
  11. 什么是 DevSecOps?系列(一)
  12. tomcat登录账户配置
  13. 新手到黑客的最全入门路径图(附全部学习资料下载)!
  14. Dapr for dotnet | 服务调用-Service invoke(HTTP协议)
  15. 和计算机相关的英文名字女孩,最好听的英文名字女孩
  16. linux intel wifi驱动,ubuntu 8.04下面 Intel WIFI link 5100无线网卡驱动安装
  17. numpy序列预处理dna序列_合成生物学快讯2019年第12期:基于DNA的分子数字数据存储...
  18. 儿童编程Scratch入门课程都学习什么内容?
  19. 转:中国人须知道的76个常识
  20. binutils java_一起编制binutils和gcc的配方?

热门文章

  1. 去除安卓apk中的广告
  2. 云开发—扫码点餐系统实战
  3. 确定性随机数发生器测试向量——DRBG-HMAC-SHA1
  4. 磁盘驱动器或Windows Home Server失败的情况挽救了我的婚姻
  5. Codeforces 1153
  6. 在微型计算机中,ram的特点是___.,2017计算机基础模拟试题「附答案」
  7. 杂谈——科比球鞋(Nike)全记录
  8. 原生js实现横向 tab 栏切换,选中项自动滚动居中
  9. openwrt之mwan3负载均衡·多线多拨
  10. jquery填充列表内容