openresty通过ffi调用一个c编写的base64动态库

base64编码的原理

  • base64不是加密,就是一种编码,将字符串的二进制按6个bit一组,每组的6个bit的形式转换一下。

  • 每组6个bit对应的字符是 有特定的映射表决定。

映射表:

字符序号
A-Z序号0-25
a-z序号26-51
0-9序号52-61
+序号62
/序号63
  • 都转成以上5种,目的是为了网络传输没有特殊字符。

  • 标准base64 不适合url中直接传输; safe_base64的做法是把最后那俩字符 +和/ 替换成 -_ 即可。解析的时候反向替换之后再base64解码。

  • 因为http传输,+号会被服务器解析成空格, 导致解析base64字符串失败。当然可以对传输的base64字符串进行url编码在传输, nginx会自动url解码。

  • c语言实现编码(3个byte拆分成4个byte):

  • 3个字节一次循环正好拆为4个字符,如果循环剩余1个字符,需要补2个=,如果剩余2个字符,需要补1个=。每个=是6位,凑成8位的倍数,因为网络传输是按8位一组传输的,所以必须是总bit数必须是8的倍数。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>


char* base64_encode(const char *p, int length, char **output, int *dlen){
    static const char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    int j = 0;
    int flag = 0;
    const char *str = p;
    int insize = length;
    char * dst = *output;
    int i = 0;
    while(i < insize){
        unsigned char c1 = (unsigned char) *str++;
        i++;

        c1 = c1 & 0xff ;
        if(i == insize){
            snprintf(*output, 5, "%c%c==",base[((c1 & 0xfc) >> 2)], 
                                        base[((c1 & 0x03) << 4)]);
            *output +=4;
            break;
        }
        unsigned char c2 = (unsigned char) *str++;
        i++;
        if(i == insize){
            snprintf(*output, 5, "%c%c%c=",base[((c1 & 0xfc) >> 2)], 
                                        base[(((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4))], 
                                        base[((c2 & 0x0f) << 2)]);
            *output +=4;
            break;
        }

        unsigned char c3 = (unsigned char) *str++;
        i++;
        snprintf(*output, 5, "%c%c%c%c",base[((c1 & 0xfc) >> 2)], 
                                    base[(((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4))], 
                                    base[(((c2 & 0x0f) << 2) | ((c3 & 0xc0) >>6))],
                                    base[(c3 & 0x3f)]);
        
        *output +=4;
    }
    **output = '\0';
    *dlen = strlen(dst);

    return dst;
}


int find_index(unsigned char c){
    static const char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    int i = 0;
    int ret = 0;
    for(i=0; i< 64; i++){
        if(base[i] == c){
            ret = i;
            break;
        }
    }

    return ret;
}

char*   base64_decode(const char *src, int len,  char **output, int *dlen){
    char *str = (char*)src;
    int i = 0;
	char *dst =  *output;
	
    while(i < len){
        int arr[4] = {0};
        int k = 0;
        while(k<4){
            char tmp = *str++;
            if(tmp != '='){
                arr[k] = find_index(tmp);
            }
            k++;
        }
        i+=4;
        //printf("%d, %d,%d,%d\n",arr[0],arr[1],arr[2],arr[3] );

        unsigned char o1 = ((arr[0]<<2) | (arr[1] & 0x30) >>4);
        unsigned char o2 = (((arr[1] & 0x0f) << 4) | ((arr[2] & 0x3c) >>2));
        unsigned char o3 = (((arr[2] & 0x03) << 6) | arr[3]);
        snprintf(*output, 4, "%c%c%c", o1,o2,o3);
        //printf("%c,%c,%c\n", o1,o2,o3);
        *output+=3;
    }

    //printf("%s \n", base64);
    *dlen = strlen(dst);
    return dst;
}


int main(int argc, char* argv[]){
    
    if(argc != 3){
        printf("提示: 输入加密选项-d或-e, 和待加密解密的参数");
        exit(-1);
    }
    if(!strcmp(argv[1], "-e")){
        int len = strlen(argv[2]);
        char *output = (char*)malloc(((len+2)/3)*4);
        char *encode_str = output;

        int dlen = 0;
        base64_encode(argv[2], len, &output, &dlen);
        printf("字符串:%s\n", argv[2]);
        printf("base64编码: %s\n", encode_str);
        free(encode_str);
    }else if(!strcmp(argv[1],"-d")){
        //const char * encode_str = "aGVsbG93b3JsZA=="; // helloworld
        char *encode_str = argv[2];
        int len = strlen(encode_str);
        char *output = (char *)malloc(((len+3) /4) *3);
        char *decode_str = output;
        int dlen = 0;
        base64_decode(encode_str, len,  &output, &dlen);
        printf("base64解码: %s\n", decode_str);
        free(decode_str);
    }else{
        printf("命令选项错误: -[de]\n");
    }

    return 0;
}


  • lua ffi编译
cd /usr/local/openresty/lualib/base64
gcc -o base64.so -fpic -shared base64.c

  • openresty 接口调用
local ffi = require "ffi"
local base64 = ffi.load("/usr/local/openresty/lualib/base64/base64.so")

ffi.cdef[[
	int base64_encode(const char *p, int length, char **output, int *dlen);
	int base64_decode(const char *src, int len,  char **output, int *dlen);
]]

local c_char = ffi.typeof("char[?]")
local c_int = ffi.typeof("int[?]")

local function base64_encode(s) 
	local buf = ffi.new(c_char, ((#s+2) / 3 ) * 4)
	local buf1= ffi.new("char *[1]", buf) -- 二级指针,如果不修改指针指向,用一级指针即可。
	local dlen = ffi.new(c_int, 1) -- ffi.new("int[1]")
	local encode_str = base64.base64_encode(s, #s, buf1, dlen)

	return ffi.string(buf, dlen[0])
end



local function base64_decode(s)
	local buf = ffi.new(c_char, ((#s+3) / 4 ) * 3)
	local buf1= ffi.new("char *[1]", buf) -- 二级指针,如果不修改指针指向,用一级指针即可。
	local dlen = ffi.new(c_int, 1) -- ffi.new("int[1]")
	local encode_str = base64.base64_decode(s, #s, buf1, dlen)
	return ffi.string(buf, dlen[0])
end

local encode = base64_encode("真的很用容易去调用一个外部 C 库函数,示例代码")
ngx.say(encode)
local decode = base64_decode(encode)
ngx.say(decode)

--[[
output:
55yf55qE5b6I55So5a655piT5Y676LCD55So5LiA5Liq5aSW6YOoIEMg5bqT5Ye95pWw77yM56S65L6L5Luj56CB
真的很用容易去调用一个外部 C 库函数,示例代码
]]--

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值