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 库函数,示例代码
]]--