当前位置:   article > 正文

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

  源文件 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;
}
  • 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
  • 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
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292

附:源代码下载

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/863859
推荐阅读
相关标签
  

闽ICP备14008679号