用于将字节进行base64编码或解码(C语言实现)

cnblogs 2024-06-13 09:39:00 阅读 58

用于将字节进行base64编码或解码(C语言实现)

用于将数据进行base64编码或解码,模块化封装, 已测试.

V1.0 2024年6月13日 发布于博客园

目录

  • base64.h
  • base64.c

基本原理见代码注释!

base64.h

#ifndef _BASE64_H

#define _BASE64_H

/**

* @file name : base64.h

* @brief : 用于将字节进行base64编码或解码

* @author : RISE_AND_GRIND@163.com

* @date : 2024年6月12日

* @version : 1.0

* @note :

* CopyRight (c) 2023-2024 RISE_AND_GRIND@163.com All Right Reseverd

*/

/**Base64基本介绍

* 什么是Base64编码?

* 编码的主要目的是在需要通过文本传输或存储二进制数据的场景中,

* 确保数据的完整性和可读性。直接使用ASCII存储二进制数据存在一些问题,

* 因为二进制数据可能包含不可打印字符或特殊字符,这些字符在某些传输媒介(如电子邮件、URL等)中可能会被误解或破坏。

* 为什么要使用Base64?

* 可读性和可传输性:

* Base64编码将二进制数据转换为可打印的ASCII字符,确保数据在传输过程中不被改变。

* 许多传输协议(如SMTP邮件协议)只支持文本数据,Base64编码使得二进制数据可以通过这些协议传输。

*

* 避免数据损坏:

* 某些传输通道可能会对非文本数据进行处理或修改,Base64编码可以避免这些问题。

*

* 兼容性:

* Base64编码后的数据可以在不同系统和平台之间无缝传输,而不会受到字符集或编码方式的影响。

*

* Base64的应用:电子邮件附件、Web数据传输(图片、文件等)、数据存储(某些数据库)、加密和签名

*/

/**Base64基本原理

* Base64(64个字符) -->2^6即6个比特-->其字符编码范围为0~63

* -->"A-Z" "a-z" "0~9" "+" "/"

* -->'A-Z' -- 编码范围 0~25

* -->'a-z' -- 编码范围 26~51

* -->'0-9' -- 编码范围 52~61

* -->'+' -- 编码范围 62

* -->'/' -- 编码范围 63

*

* 注意, 最后不足4字符会以'='补齐

*

* 例如: 将ASCII码的"Man"转换为Base64编码为TWFu

* M---->ASCII对应值: A(65)+12 = 77 --->十六进制:0x4D--->二进制:0100 1101

* a---->ASCII对应值: a(97)+0 = 97 --->十六进制:0x61--->二进制:0110 0001

* n---->ASCII对应值: a(97)+13 = 110 --->十六进制:0x6E--->二进制:0110 1110

*

* 在内存中(ASCII) :0100 1101 0110 0001 0110 1110

* 6位划分为Base64 : 010011| 010110| 000101| 101110

* 但内存是以字节为单位 :00010011|00010110|00000101|00101110

* Base64显示 : T(19) W(22) F(5) u(46)

*

* 所以每3个字节ASCII码会生成4个字节的Base编码

*/

/***************************************头文件***************************************/

#include <stdio.h>

#include <string.h>

/***************************************END******************************************/

// 查找Base64字符在表中的位置, 进行数值还原

int base64_char_value(char c);

/**将字符串进行Base64编码

* @name base64_encode

* @brief 将字符串进行Base64编码

* @param input 输入的ASCII字符串

* @param output 得到的base64编码

* @date 2024年6月12日

* @version 1.0

* @note

*/

void base64_encode(const unsigned char *input, char *output);

/**将字符串进行Base64解码

* @name base64_decode

* @brief 将字符串进行Base64解码

* @param input 输入的base64编码

* @param output 得到的ASCII字符串

* @date 2024年6月12日

* @version 1.0

* @note

*/

void base64_decode(const char *input, unsigned char *output);

#endif

base64.c

/**

* @file name : base64.c

* @brief : 用于将字节进行base64编码或解码

* @author : RISE_AND_GRIND@163.com

* @date : 2024年6月12日

* @version : 1.0

* @note :

* CopyRight (c) 2023-2024 RISE_AND_GRIND@163.com All Right Reseverd

*/

#include "../../include/utilities/base64.h"

// Base64字符表, 用于编码和解码 static限制为文件域

static const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// 查找Base64字符在表中的位置, 进行数值还原

int base64_char_value(char c)

{

if (c >= 'A' && c <= 'Z') // 'A'到'Z'的值为0到25

return c - 'A';

if (c >= 'a' && c <= 'z') // 'a'到'z'的值为26到51

return c - 'a' + 26;

if (c >= '0' && c <= '9') // '0'到'9'的值为52到61

return c - '0' + 52;

if (c == '+') // '+'的值为62

return 62;

if (c == '/') // '/'的值为63

return 63;

return -1; // 非Base64字符返回-1

}

/**将字符串进行Base64编码

* @name base64_encode

* @brief 将字符串进行Base64编码

* @param input 输入的ASCII字符串

* @param output 得到的base64编码

* @date 2024年6月12日

* @version 1.0

* @note

*/

void base64_encode(const unsigned char *input, char *output)

{

int length = strlen((const char *)input); // 计算输入字符串的长度

int i = 0; // 计数器

int j = 0;

unsigned char a3[3] = {0}; // 每次输入3个ASCII码字节缓冲区, 3个ASCII码可生成4个Base64编码

unsigned char a4[4] = {0}; // 每次输出4个Base64字符缓冲区

while (length--) // 输入字符串的长度每次载入3个字节, 即长度每次-3

{

a3[i++] = *(input++); // 载入字符到输入数组中

if (i == 3) // 若输入了3个字符, 则触发编码

{

/** a3[0] a3[1] a3[2]

* 在内存中(ASCII) :0100 1101 0110 0001 0110 1110

* 6位划分为Base64 : 010011| 010110| 000101| 101110

*/

a4[0] = (a3[0] & 0xfc) >> 2; // a3[0] & 11111100 取a3[0]的前6位

a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); // 取a3[0]的后2位和a3[1]的前4位

a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); // 取a3[1]的后4位和a3[2]的前2位

a4[3] = a3[2] & 0x3f; // 取a3[2]的后6位

for (i = 0; i < 4; i++) // 每次输出4个编码后的字符

{

*output++ = base64_table[a4[i]]; // 将编码后的Base64值映射到Base64字符表, 转换为ASCII码的形式显示(只是显示, 内容是Base64)

}

i = 0; // 重置计数器

}

}

if (i) // 若位数不足3个字节

{

for (j = i; j < 3; j++) // 用0填充不足的字节部分

{

a3[j] = '\0';

}

// 同上操作

a4[0] = (a3[0] & 0xfc) >> 2;

a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);

a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);

a4[3] = a3[2] & 0x3f;

// 将已编码好的部分输出, +1是因为若只有一个字节也至少生成2个字符, 始终会+1

for (j = 0; j < (i + 1); j++)

{

*output++ = base64_table[a4[j]];

}

while ((i++ < 3))

{

*output++ = '='; // 用'='填充不足的部分并输出

}

}

*output = '\0'; // 输出字符串完毕

}

/**将字符串进行Base64解码

* @name base64_decode

* @brief 将字符串进行Base64解码

* @param input 输入的base64编码

* @param output 得到的ASCII字符串

* @date 2024年6月12日

* @version 1.0

* @note

*/

void base64_decode(const char *input, unsigned char *output)

{

int i = 0; // 计数器

int j = 0;

unsigned char a4[4] = {0}; // 每次输入4个Base64字符缓冲区

unsigned char a3[3] = {0}; // 每次输出3个ASCII码字节缓冲区, 4个Base64编码可生成3个ASCII码

while (*input)

{

for (i = 0; i < 4; i++) // 以4个base字符为单位进行处理

{

if (*input == '=') // 若是末尾

{

a4[i] = 0; // 转换为'\0'

}

else // 若不是末尾

{

a4[i] = base64_char_value(*input);

}

input++; // 继续读入1个字符

}

a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); // 解码第一个字节 取消移位

a3[1] = ((a4[1] & 0x0f) << 4) + ((a4[2] & 0x3c) >> 2); // 解码第二个字节

a3[2] = ((a4[2] & 0x03) << 6) + a4[3]; // 解码第三个字节

for (j = 0; j < 3; j++)

{

*output++ = a3[j]; // 将解码后的字节写入输出

}

}

*output = '\0'; // 结束字符串

}

#if 0

int main()

{

// 测试Base64编码

const char *input_encode = "我爱中国"; // 正确值应该是"5oiR54ix5Lit5Zu9"

char output_encode[50]; // 需要足够大的数组来存储Base64编码后的字符串

base64_encode((const unsigned char *)input_encode, output_encode);

printf("Base64 Encoded: %s\n", output_encode);

// 测试Base64解码

const char *input_decode = "6Zey5p2l5peg5LqL5pG46bG85pe2LCDlip7lhazlrqTlhoXmhI/mrLLnprvjgIIKIOaJi+aPoem8oOagh+i9u+i9u+a7kSwg55y86KeC5bGP5bmV5b+D6Ieq5Zek44CCCiDlkIzkuovlv5nnoozlv5nlvpfntK8sIOaIkeWNtOmXsumAuOW/g+asouWWnOOAggog5oyH5bCW6L275pWy6ZSu55uY5aOwLCDpsbzmuLjmsLTkuK3ku7vmhI/lrInjgIIKIOS4iuWPuOW/veeEtuS4tOaXtuiHsywg5oiR5YyG5b+Z5oqK6bG86JeP56We56eY44CCCiDpnaLlrrnkuKXogoPnnLzlpoLnlLUsIOe6teeEtuaIkeW/g+aFjOWmgum4oeOAggog5pil6aOO5ouC6Z2i5b+Y5Yqz6IumLCDor5fmhI/nm47nhLblv4PmrKLkuZDjgIIKIOS4gOeJh+i9u+advuWcqOW/g+WktCwg5pG46bG85Ly85LmO5peg56m35LmQ44CC";

unsigned char output_decode[1024]; // 需要足够大的数组来存储解码后的数据

base64_decode(input_decode, output_decode);

printf("Base64 Decoded:\n %s\n", output_decode);

return 0;

}

#endif



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。