对基于Lua和Nginx的iOS应用数据的加密框架

预答辩归来,主管给了我一个新任务,这是实习以来的第三个任务了。任务仍然很简单,就是对ios应用中的一些重要数据进行DES加密。

iOS的界面通过Webview形式展示,在web页中通过JS调用lua脚本对重要数据进行读取和存放,所以加密模块的函数必须能够在lua脚本中调用。咋一看,将函数增加到“lua调用库”里是一个直接的方法。

第一种尝试:增加lua的C API

     通过对lua(programming with lua中文版,新浪资料)的基本学习了解到,lua作为一种简单、高效执行、跨平台的嵌入式脚本语言,其主要由包括string、io等基本函数实现的标准库构成,全部代码均有C语言实现。lua语言的另外一个特点是其可扩展性,通过函数栈的形式可以和所有的主流语言进行交互,可以在lua脚本中调用其他语言构建的扩展库,也可以在其他语言中通过lua执行环境调用lua中的基本函数库。在这里,为了完成加密任务,我选择了基于Lua的C扩展库来完成。开始还有一种想法就是直接在lua中通过lua的自定义数据结构像基本库一样去实现加密模块,但是考虑到lua升级的维护性和时间安排,最终放弃了这种选择。目标确定之后,接下来就是开始编写基于Lua的DES扩展库,所有的辅助函数均可以用C语言实现,只需要稍微改变一下lua调用函数的形式即可。因为lua调用函数最终会在lua脚本中调用,所以其函数所有参数的获得都是从lua环境中获得,lua提供了一个lua环境,其所有的参数都在称作lua_State *L的参数里,可以通过luaL_checkNumber(L, index), luaL_ChechString(L,index),分别读取函数参数,然后通过注册所有的lua调用函数,注册扩展库。这样关于DES的扩展库的代码工作就完成了。具体代码如下所示:

static int DES_Encrypt(lua_State *L);
static int DES_Decrypt(lua_State *L);


//加密文件    
static int DES_Encrypt(lua_State *L){
    
    const char * plainStr = luaL_checkstring(L, 1);
    int len_plainStr = luaL_checknumber(L, 2);
    const char * keyStr = DESKEY;
    
    int len_cipherStr = (len_plainStr + 8 - len_plainStr % 8);
    char *cipherStr = (char *)malloc(sizeof(char) * len_cipherStr);
    
    ElemType plainBlock[8],cipherBlock[8],keyBlock[8];  
    ElemType bKey[64];  
    ElemType subKeys[16][48];  
    
    //设置密钥  
    memcpy(keyBlock,keyStr,8);  
    //将密钥转换为二进制流  
    Char8ToBit64(keyBlock,bKey);  
    //生成子密钥  
    DES_MakeSubKeys(bKey,subKeys);  
    
    int len_remain = len_plainStr;
    while(len_remain > 0)
    {
        if(len_remain >= 8)
            memcpy(plainBlock, plainStr+(len_plainStr-len_remain), 8);
        else{
            //读取剩下的字节,并补齐
            memcpy(plainBlock, plainStr+(len_plainStr-len_remain), len_remain);
            memset(plainBlock+len_remain, '\0', 8-len_remain);
            plainBlock[7] = 8 - len_remain;
        }
        //加密每个block
        DES_EncryptBlock(plainBlock,subKeys,cipherBlock); 
        //将生成的密文存入到一个数据结构中去
        memcpy(cipherStr+(len_plainStr-len_remain), cipherBlock, 8);
        len_remain = len_remain - 8;
    }
    
    lua_pushlstring(L, cipherStr, len_cipherStr);
    free(cipherStr);
    
    return 1;  
}  

//解密文件  
//int DES_Decrypt(char *cipherFile, char *keyStr,char *plainFile){  
static int DES_Decrypt(lua_State *L){
    const char * cipherStr = luaL_checkstring(L, 1);
    int len_cipherStr = luaL_checknumber(L, 2);
    const char * keyStr = DESKEY;
    
    //如果解密字符串不是8的倍数,说明该字符串未经过加密
    int len_plainStr = len_cipherStr;
    char *plainStr = (char *) malloc (sizeof(char) * len_plainStr);
    
    ElemType plainBlock[8],cipherBlock[8],keyBlock[8];  
    ElemType bKey[64];  
    ElemType subKeys[16][48];  
    
    //设置密钥  
    memcpy(keyBlock,keyStr,8);  
    //将密钥转换为二进制流  
    Char8ToBit64(keyBlock,bKey);  
    //生成子密钥  
    DES_MakeSubKeys(bKey,subKeys);  
    
    int len_remain = len_cipherStr;
    while(len_remain > 0){  
        //密文的字节数一定是8的整数倍  
        memcpy(cipherBlock, cipherStr+(len_cipherStr-len_remain), 8);  
        DES_DecryptBlock(cipherBlock,subKeys,plainBlock);                         
        memcpy(plainStr+(len_cipherStr-len_remain), plainBlock, 8);
        len_remain = len_remain - 8;
    }  
    //判断末尾是否被填充  
    if(plainBlock[7] < 8){
        len_plainStr = len_plainStr - plainBlock[7];
    }
    
    lua_pushlstring(L, plainStr, len_plainStr);
    free(plainStr);    

    return 1;  
} 

//将定义的函数名集成到一个结构数组中去,建立 lua 中使用的方法名与 C 的函数名的对应关系  
static const struct luaL_reg luades [] = {
    {"lsin", l_sin},
    {"lDesEncode", DES_Encrypt},
    {"lDesDecode", DES_Decrypt},
    {NULL, NULL} /* 必须以NULL结尾 */
};


//库打开时的执行函数(相当于这个库的 main 函数),执行完这个函数后, lua 中就可以加载这个 so 库了
int luaopen_luades (lua_State *L) 
{
    luaL_openlib(L, "myLuaDes", luades, 0);
    return 1;
}
接下来就是编译,首先编译了一个mac版本的动态库。就是通过将基于lua的des函数编译成动态库(.so形式),然后在lua的解释器中加载lua_des扩展库,通过自定义的扩展库别名,调用自定义的函数别名进行调用。加密解密后的内容正确,说明函数功能完成。

 gcc lDes.c -fPIC -W -Waggregate-return -Wcast-align -Wmissing-prototypes -Wnested-externs -Wshadow -Wwrite-strings -pedantic  -I /Users/whaty/Desktop/LIBLUA/LIBLUA -L/Users/whaty/Desktop/LIBLUA/LIBLUA -shared -o libLuaDes.so -llua
 package.loadlib("/Users/whaty/Desktop/LuaDes/LuaDes/libLuaDes.so", "luaopen_luades")()
 print(mylib1.lsin(10))
但是现在的目标是需要在ipad应用中加载这个库,这个.so形式的扩展库肯定不能用,需要编译一个ipad版本的动态库。在ios中,动态库是基于.dylib后缀名形式,如何将一个c文件编译成ipad动态库的形式,这是一个思路,但是当前ios应用已有的一个架构是将lua标准库编译到Nginx中的库里,通过熟悉Nginx中的模块化思路我采取下面一种思路。

另一种尝试:增加Nginx中Lua模块的库函数功能

Nginx作为一种高性能的开源web服务器,采用了模块化框架,所有模块都是通过静态编译,当启动nginx时,会自动加载所有模块。其中Nginx_Lua模块提供了配置指令和Nginx API,配置指令是在nginx中使用,Nginx API是用来在Lua脚本中访问Nginx中的变量和函数。现在我们的目标是如何在Nginx中lua模块中加入一个新的Nginx API函数。

下面我们先来关注一下Nginx中Lua模块的运行机制。Nginx中的每个Worker进程使用一个lua虚拟机,工作进程中的所有协程共享虚拟机。将Nginx中的lua API封装好之后注入到lua的VM中就可以在lua代码中进行访问了。我没有直接新开辟一个nginx api模块,而是在原来nginx.req API中加入一个DES模块。加密函数仍然不变,只是改变了以下注册函数,注册函数如下:

void
ngx_http_lua_inject_req_args_api(lua_State *L)
{
    lua_pushcfunction(L, ngx_http_lua_ngx_req_set_uri_args);
    lua_setfield(L, -2, "set_uri_args");

    lua_pushcfunction(L, ngx_http_lua_ngx_req_get_uri_args);
    lua_setfield(L, -2, "get_uri_args");

    lua_pushcfunction(L, ngx_http_lua_ngx_req_get_uri_args);
    lua_setfield(L, -2, "get_query_args"); /* deprecated */

    lua_pushcfunction(L, ngx_http_lua_ngx_req_get_post_args);
    lua_setfield(L, -2, "get_post_args");
    
    lua_pushcfunction(L, DES_Encrypt);
    lua_setfield(L, -2, "lDesEncode");
    
    lua_pushcfunction(L, DES_Decrypt);
    lua_setfield(L, -2, "lDesDecode");
    //ngx.req.get_uri_args
}
注册完毕之后,就可以在lua脚本中通过ngx.req.lDesEncode() 和 ngx.req.lDesDecode()两个函数进行加密和解密了。

上面只是本人对lua和nginx的初步了解,欢迎指教。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值