首页 > 其他分享 >用于将字节进行base64编码或解码(C语言实现)

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

时间:2024-06-13 09:10:57浏览次数:21  
标签:编码 Base64 解码 base64 C语言 a3 a4 ASCII

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

目录

基本原理见代码注释!

base64.h

#ifndef _BASE64_H
#define _BASE64_H
/**
 * @file name : base64.h
 * @brief     : 用于将字节进行base64编码或解码
 * @author    : [email protected]
 * @date      : 2024年6月12日
 * @version   : 1.0
 * @note      :
 * CopyRight (c)  2023-2024   [email protected]   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    : [email protected]
 * @date      : 2024年6月12日
 * @version   : 1.0
 * @note      :
 * CopyRight (c)  2023-2024   [email protected]   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

标签:编码,Base64,解码,base64,C语言,a3,a4,ASCII
From: https://www.cnblogs.com/zqingyang/p/18245191

相关文章

  • zzulioj1042答案c语言
    ​(方法一:使用函数体)#include<stdio.h>#include<math.h>intt;//t输入这里的t是一个全局变量doubleturn(doublem,doublen,doublea,doublesum,doubleflag);intmain(){doublem,n,a,sum=0,flag=1;//m分子,n分母,a项数,sum和,flag变换符号scanf("%d",......
  • 动态内存管理<C语言>
    导言       在C语言学习阶段,指针、结构体和动态内存管理,是后期学习数据结构的最重要的三大知识模块,也是C语言比较难的知识模块,但是“天下无难事”,只要认真踏实的学习,也能解决,所以下文将介绍动态内存管理涉及到的一些函数以及概念。目录导言为什么存在动态内存管理......
  • What-is-base64-code
    Base64编码和解码Base64是一种基于64个可打印字符来表示二进制数据的编码方式。它通常用于在文本数据中传输二进制数据,例如电子邮件和URL。Base64编码过程数据分割:将输入的二进制数据按每24位(3字节)一组分割。如果最后一组不足24位,用0进行填充。每6位一组:将每24位的数据再分......
  • 初阶C语言(01)—学习笔记
    if语言if语句其一C语言被称为结构化的程序设计语言,包括顺序结构、选择结构(ifswitch)和循环结构(for while dowhile)。因为今天要下雨,所以必须带伞。这就是一个简单的选择语句。例如:如果你的年龄大于18岁,那么输出成年。#include<stdio.h>intmain(){ intage=20;......
  • 零基础非科班也能掌握的C语言知识21 编译链接(介于作者实力有限并且没有可以演示的过程
    编译链接1.翻译环境和运行环境2.翻译环境2.1编译2.1.1预处理(预编译)2.1.2编译2.1.3汇编2.2链接3.运行环境1.翻译环境和运行环境在ANSIC的任何⼀种实现中,存在两个不同的环境。编译环境运行环境2.翻译环境翻译环境由编译和链接两个大的过程组成的,而编译又可......
  • C语言指针介绍加练习
    #指针相关介绍定义    指针(Pointer),通常用于数据的间接访问,指针存储的是指向变量的首地址,16位平台就是2位,如果在32位平台,地址就是4个字节,如果实在64位平台,地址就是8个字节(1Byte=8bit),Int类型4Byte char类型1Byte这个是变量在内存中,分配的地址大小,在内存中一个By......
  • Base64编码解码流程的初步学习
    目录什么是Base64编码?为什么要学习Base64编码?Base64编码基础原理介绍Base64编码组成Base64编码索引表Base64编码规则Base64编码过程简记编码流程实战Base64编码(不同情况举例说明)1.待编码字符数量为3的倍数2.待编码字符数量不为3的倍数Base64解码原理简单介绍Base64解码过程Base6......
  • C语言王国——数组的旋转(轮转数组)三种解法
    一、题目给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。示例1:输入:nums=[1,2,3,4,5,6,7],k=3输出:[5,6,7,1,2,3,4]解释:向右轮转1步:[7,1,2,3,4,5,6]向右轮转2步:[6,7,1,2,3,4,5]向右轮转3步:[5,6,7,1,2,3,4]示例......
  • C语言字符串处理函数strstr的用法
    C语言字符串处理函数strstr的用法在C语言中,strstr函数是一个字符串处理函数,用于在一个字符串(称为“主字符串”)中查找另一个字符串(称为“子字符串”)的首次出现。如果找到子字符串,则该函数返回一个指向主字符串中子字符串首次出现位置的指针;如果没有找到,则返回NULL。函数的原型定......
  • c语言开发 php扩展 sm4
    首先php可以直接调用openssl直接进行sm4sm3的加密如:openssl_encrypt($plaintext,'sm4-cbc',$key,OPENSSL_RAW_DATA,$iv);openssl_digest('123','sm3')php如果直接调用sm2需要统一使用openssl的evp接口openssl1.1的源码在sm2_crypt文件里面此处只是学习/*gmteste......