base64编解码介绍

2019-11-30  本文已影响0人  突击手平头哥

base64编解码介绍

使用

  最近在工作中遇到了需要在url中传递参数的问题, 所以用到了base64编码.
  Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。 Base64并不是压缩算法, 也不是HASH算法, 而是根据一定可以进行无损的编码解码用于数据传递.

规则

注意

原理

编码实现

由于笔者需要用lua实现, 所以这里使用C实现一个标准的, 然后使用lua实现一个可以用于HTTP的; 代码上基本相差不大

#include <stdlib.h>

const char *base64_list = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789+/";
const char base64_last  = '=';

char* base64_enc(const char* data, int len, char *dst)
{
    if(!data || len <= 0)   return NULL;

    int new_len = (len * 4) / 3 + 5;
    if(!dst)
        dst = (char*)calloc(new_len, 1);

    int index = 0;

    int i = 0;
    for(i = 0; i < len; i+=3)
    {
        char tmp[3] = { 0 };
        for(int j = 0; j < 3 && j < (len-i); j++)
        {
            tmp[j] = data[i+j]; 
        }
        dst[index++] = base64_list[tmp[0]>>2];
        dst[index++] = base64_list[((tmp[0]&3)<<4) + (tmp[1]>>4)];
        dst[index++] = base64_list[((tmp[1]&0xf)<<2) + (tmp[2]>>6)];
        dst[index++] = base64_list[tmp[2]&0x3f];
    }
    //注意这里是允许data不以\0结尾的

    if(i == len + 1)
        dst[index - 1] = '=';
    else if(i == len + 2)
        dst[index - 1] = dst[index - 2] = '=';

    return dst; 
}

char* base64_dec(const char *data, int len, char *dst)
{
    if(!data || len < 0)
        return NULL;
    int new_len = (len * 3) / 4 + 3;
    if(!dst)
        dst = (char*)calloc(new_len, 1);

    u_int8_t map[128] = { 0 };
    for(int i = 0; i < 64; i++)
    {
        map[base64_list[i]] = i;
    }

    if(data[len-1] == '=') len--;
    if(data[len-2] == '=') len--;

    int index = 0;
    for(int i = 0; i < len; i+=4)
    {
        u_int8_t tmp[4] = { 0 };
        for(int j = 0; j < 4 && j < (len - i); j++)
        {
                tmp[j] = map[data[i+j]];
        }

        dst[index++] = (tmp[0]<<2) + (tmp[1]>>4);
        if(len - i > 2)
            dst[index++] = (tmp[1]<<4) + (tmp[2]>>2);
        if(len - i > 3)
            dst[index++] = (tmp[2]<<6) + tmp[3];

    }

    return dst;
}

#ifdef TEST_BASE64
#include <string.h>
#include <stdio.h>
    int main()
    {
        char buffer[128];
        scanf("%s", &buffer);

        char *enc = base64_enc(buffer, strlen(buffer), NULL);
        printf("base encode: %s\n", enc);;

        char *dec = base64_dec(enc, strlen(enc), NULL);
        printf("base decode: %s\n", dec);

        return 1;
    }

#endif

额外lua的实现, 可用于URL传递

local b = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_/'

-- encoding
function enc(data)
    return ((data:gsub('.', function(x) 
        local r, a = '', x:byte()
        for i = 8, 1, -1 do
            r = r .. (a % 2^i - a % 2^(i-1) > 0 and '1' or '0')
        end
        --1, 高字节在前
        --2,  a%2^4=a%00010000=0000xxxx相当于和00001111进行与操作, (a % 2^i - a % 2^(i-1) > 0就可以判断第i位是否是1

        return r
    end) .. '0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
        --每三个字节转变为4个字节, 如果多出1个8位扩展为12位, 如果多出2个16位扩展为18位; 所以最多添加4个0
        if (#x < 6) then 
            return '' 
        end

        local index = 0
        for i = 1, 6 do 
            index = index + (x:sub(i, i) == '1' and 2^(6-i) or 0)
        end

        return b:sub(index+1, index+1)
    end))
end

-- decoding
function dec(data)
    data = string.gsub(data, '[^'..b..']', '')
    --只允许编码的字符
    return (data:gsub('.', function(x)
        local ret, f = '', (b:find(x)-1)
        for i=6, 1, -1 do 
            ret = ret .. (f % 2^i - f % 2^(i-1) > 0 and '1' or '0')
            --将数字转为二进制
        end
        return ret
    end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
        if (#x ~= 8) then 
            return '' 
        end
        local c = 0
        for i = 1, 8 do 
            c = c + (x:sub(i,i) == '1' and 2^(8-i) or 0) 
        end
        --每8位作为一个二进制数转变为10进制
        return string.char(c)
        --将ASCII重新转变为字符
    end))
end

ps: 注意 f % 2^i - f % 2^(i-1) 适用于判断指定位置是否为1

上一篇下一篇

猜你喜欢

热点阅读