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

一、前言

  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 - 16
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,                //17 - 32
    0,0,0,0,0,0,0,0,0,0,0,62,0,0,0,63,              //33 - 48
    52,53,54,55,56,57,58,59,60,61,0,0,0,0,0,0,      //49 - 64
    0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,           //65 - 80
    15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,     //81 - 96
    0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, //97 - 112
    41,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

  • 12
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
以下是C语言实现base64编码解码的示例代码: ```c #include <stdio.h> #include <string.h> #include <stdlib.h> // Base64编码表 static const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // Base64解码表 static const char base64_decode_table[] = { 62, -1, -1, -1, 63, // '+', '/', and 0x3D are special 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9', '=', and 'A'-'Z' -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; // Base64编码函数 char* base64_encode(const unsigned char *data, size_t input_length, size_t *output_length) { *output_length = 4 * ((input_length + 2) / 3); // 计算编码后字符串长度 char *encoded_data = malloc(*output_length + 1); // 分配内存 if (encoded_data == NULL) { return NULL; } // 编码 for (size_t i = 0, j = 0; i < input_length;) { uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0; uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0; uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0; uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; encoded_data[j++] = base64_table[(triple >> 3 * 6) & 0x3F]; encoded_data[j++] = base64_table[(triple >> 2 * 6) & 0x3F]; encoded_data[j++] = base64_table[(triple >> 1 * 6) & 0x3F]; encoded_data[j++] = base64_table[(triple >> 0 * 6) & 0x3F]; } // 添加填充字符 for (size_t i = 0; i < (*output_length - input_length % 3) % 3; i++) { encoded_data[*output_length - 1 - i] = '='; } encoded_data[*output_length] = '\0'; return encoded_data; } // Base64解码函数 unsigned char* base64_decode(const char *data, size_t input_length, size_t *output_length) { if (input_length % 4 != 0) { return NULL; } *output_length = input_length / 4 * 3; // 计算解码后字节数 if (data[input_length - 1] == '=') { (*output_length)--; } if (data[input_length - 2] == '=') { (*output_length)--; } unsigned char *decoded_data = malloc(*output_length + 1); // 分配内存 if (decoded_data == NULL) { return NULL; } // 解码 for (size_t i = 0, j = 0; i < input_length;) { uint32_t sextet_a = data[i] == '=' ? 0 & i++ : base64_decode_table[(int)data[i++]]; uint32_t sextet_b = data[i] == '=' ? 0 & i++ : base64_decode_table[(int)data[i++]]; uint32_t sextet_c = data[i] == '=' ? 0 & i++ : base64_decode_table[(int)data[i++]]; uint32_t sextet_d = data[i] == '=' ? 0 & i++ : base64_decode_table[(int)data[i++]]; uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6); if (j < *output_length) { decoded_data[j++] = (triple >> 2 * 8) & 0xFF; } if (j < *output_length) { decoded_data[j++] = (triple >> 1 * 8) & 0xFF; } if (j < *output_length) { decoded_data[j++] = (triple >> 0 * 8) & 0xFF; } } decoded_data[*output_length] = '\0'; return decoded_data; } int main() { char *data = "Hello, world!"; size_t data_length = strlen(data); // 编码 size_t encoded_length; char *encoded_data = base64_encode((const unsigned char*)data, data_length, &encoded_length); printf("Base64 encoded data: %s\n", encoded_data); // 解码 size_t decoded_length; unsigned char *decoded_data = base64_decode(encoded_data, encoded_length, &decoded_length); printf("Base64 decoded data: %s\n", decoded_data); free(encoded_data); free(decoded_data); return 0; } ``` 上述代码中,`base64_encode`函数用于将二进制数据编码为Base64字符串,`base64_decode`函数用于将Base64字符串解码为原始的二进制数据。在编码时,函数会将每3个字节的二进制数据转换为4个Base64字符,如果遇到不足3个字节的末尾数据,则会用`=`字符进行填充。在解码时,函数会将每4个Base64字符转换为3个字节的二进制数据,如果遇到末尾的`=`字符,则会忽略它们。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶落花枯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值