在skynet中嵌入加密算法 https://github.com/luke-park/SecureCompatibleEncryptionExamples
-
在skynet中添加代码:
[root@localhost wtserver]# tree 3rd 3rd lua-cryption/ ├── cryptionlib.c ├── SCEE.c └── SCEE.h lua-filesystem/ ├── lfs.c ├── lfs.def └── lfs.h
-
修改skynet的makefile
CSERVICE = snlua logger gate harbor LUA_CLIB = skynet \ client \ bson md5 sproto lpeg cjson cryption lfs $(TLS_MODULE) $(LUA_CLIB_PATH)/cryption.so : 3rd/lua-cryption/cryptionlib.c 3rd/lua-cryption/SCEE.c | $(LUA_CLIB_PATH) $(CC) $(CFLAGS) $(SHARED) -I3rd/lua-cryption $^ -o $@ -lcrypto -lssl -ldl $(LUA_CLIB_PATH)/lfs.so : 3rd/lua-filesystem/lfs.c | $(LUA_CLIB_PATH) $(CC) $(CFLAGS) $(SHARED) -I3rd/lua-filesystem $^ -o $@
-
在skynet中使用案例:
在skynet中嵌入文件系统 https://github.com/keplerproject/luafilesystem
- 参考在项目中嵌入加密算法,将文件系统添加至skynet中。
- 文件系统可以参考 库的说明文档。
lua源码修改方案一:
参考博客: http://just4coding.com/2016/11/15/luajit-encrypt/
思路:检查文件是否为加密文件,将加密文件读取出后解密,并存入到临时文件中。将临时文件的句柄替换 lf.f 的句柄
方案已废弃: 临时文件的创建会导致代码泄露。
- luaL_loadfilex 函数中添加如下代码:
// lua代码
lua_pushfstring(L, "@%s", filename);
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
// 新增加代码
// 检查文件是否为加密文件, 加密文件需要嗲用解密接口
//char file_header[FILE_HEADER_LEN];
char *file_header = malloc(FILE_HEADER_LEN);
size_t sz = fread(file_header, sizeof(char), FILE_HEADER_LEN, lf.f);
if (sz == FILE_HEADER_LEN) {
if (memcmp(file_header, "wt_cipher_lua_file\n", FILE_HEADER_LEN - 1) == 0) {
// lf.f = lf.f
lf.f = decrypt_file(lf.f);
}
}
free(file_header);
fseek(lf.f, 0L, SEEK_SET);
- decrypt_file 的实现:
static FILE *decrypt_file(FILE *ofp)
{
int fd, len;
size_t sz;
FILE *fp;
unsigned char *buf, *obuf;
char file_temp[] = "/tmp/luajit-XXXXXX";
fp = NULL;
buf = NULL;
obuf = NULL;
fd = -1;
fseek(ofp, 0L, SEEK_END);
sz = ftell(ofp);
obuf = malloc(sz);
if (obuf == NULL) {
goto failed;
}
fseek(ofp, 0L, SEEK_SET);
if (fread(obuf, 1, sz, ofp) < sz) {
goto failed;
}
fclose(ofp);
ofp = NULL;
buf = blowfish_decrypt(obuf + FILE_HEADER_LEN,
sz - FILE_HEADER_LEN,
g_key,
g_iv,
&len);
if (buf == NULL) {
goto failed;
}
free(obuf);
obuf = NULL;
fd = mkstemp(file_temp);
if (fd < 0) {
goto failed;
}
unlink(file_temp);
fp = fdopen(fd, "wb+");
if (fp == NULL) {
goto failed;
}
fwrite(buf, 1, len, fp);
free(buf);
buf = NULL;
return fp;
failed:
if (fp) {
fclose(fp);
}
if (ofp) {
fclose(ofp);
}
if (obuf) {
free(obuf);
}
if (buf) {
free(buf);
}
return NULL;
}
lua源码修改方案二:
思路:修改代码读取函数。lua文件文段加密,设置分段标识。
方案已废弃:lua代码文件读取单次 BUFSIZ = 512, 并且后序处理流程复杂!代码修改过多,担心修改后影响后序流程。(能力不够)
typedef struct LoadF {
int n; /* number of pre-read characters */
FILE *f; /* file being read */
char buff[BUFSIZ]; /* area for reading file */
} LoadF;
static const char *getF (lua_State *L, void *ud, size_t *size) {
LoadF *lf = (LoadF *)ud;
(void)L; /* not used */
if (lf->n > 0) { /* are there pre-read characters to be read? */
*size = lf->n; /* return them (chars already in buffer) */
lf->n = 0; /* no more pre-read characters */
}
else { /* read a block from file */
/* 'fread' can return > 0 *and* set the EOF flag. If next call to
'getF' called 'fread', it might still wait for user input.
The next check avoids this problem. */
if (feof(lf->f)) return NULL;
*size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */
}
return lf->buff;
}
Lua中文件加密流程:
--[[
auth:zlf
date: 2021.12.28
note: 对指定路径内所有的文件加密,按原文件子路径保存在特定路径中。
]]
local lfs = require "lfs"
local cryption = require "cryption"
local M = {}
local l_Api = {}
-- 请勿改动, 改动后请随便改动 lua 的c代码相应文件
local l_CiphertextHead = "--jm_cipher_lua_file\n"
--[[
@note 检查该文件是否在为指定的格式文件
@param tbFileType 需要的文件类型
@param sFileName 被检测的文件
@return true: 合适的文件
]]
function l_Api.contain_file_type(tbFileType, sFileName)
if (not tbFileType) or #tbFileType == 0 then
return true
end
-- 只搜索文件尾部
local sFileLen = string.len(sFileName)
local nFindPlace = sFileLen
for _, sType in pairs(tbFileType) do
if string.find(sFileName, sType, (nFindPlace-string.len(sType)) , true) then
return true
end
end
end
--[[
@note 扫描指定目录的文件(可指定文件类型)
@param sRootPath 需要扫描的目录
@param tbAllFilePath 扫描到的文件存放
@param tbFileType 需要的文件类型
@return nil
]]
function l_Api.get_all_files(sRootPath, tbAllFilePath, tbFileType)
for entry in lfs.dir(sRootPath) do
if string.sub(entry,1,1) ~= "." then
local sPath = sRootPath.."/"..entry
local sAttr = lfs.attributes(sPath)
assert(type(sAttr)=="table") --如果获取不到属性表则报错
if(sAttr.mode == "directory") then
l_Api.get_all_files(sPath, tbAllFilePath, tbFileType) --自调用遍历子目录
elseif sAttr.mode=="file" then
if l_Api.contain_file_type(tbFileType, sPath) then
table.insert(tbAllFilePath,sPath)
end
end
end
end
end
--[[
@TODO: 在 sRootDir目录下, 创建 sDirPath 中所有的目录
]]
function l_Api.mkdir(sRootDir, sDirPath)
-- for sDir in string.gmatch(sDirPath, "(/%g+/)") do
-- log_info("DDDDDDDDDDDD ", sDir)
-- end
local s = 0
-- local e = 0
local bSign = false
local sCreatePath
while true do
local n = string.find(sDirPath, "/", s+1)
s = n
if s == nil then
break
end
-- 创建目录
if bSign then
sCreatePath = sRootDir .. string.sub(sDirPath, 1, s)
-- log_info("DDDDDDDDDDDD ", sCreatePath)
local tbRet = {lfs.mkdir(sCreatePath)}
-- log_info("############## ", table.printT(tbRet), sCreatePath)
if not tbRet[1] and (tbRet[3] or 0) ~= 17 then -- 17: 文件夹已经存在
assert(false, "Can't create dir faile " .. sCreatePath)
end
end
bSign = true
end
end
--[[
@TODO: 对指定路径的文件进行加密, 加密后存放到指定路径中。可指定文件的需要转换的文件类型 2021-12-28 14:51:42
@sSpecifyPathSource: 加密源目录 /data/jm/jmserver/jm
@sSpecifyPathTarget: 加密后输出根目录(需要手动创建好改目录) /data/jm/jmserver/jm/jm_encrypt
@sPassWord: 密码
@tbFileType: 需要的文件类型(不指定,所有文件都会被转换)
@return
@
]]
function M.encrypt_path_all_files(sSpecifyPathSource, sSpecifyPathTarget, sPassWord, tbFileType)
if not sSpecifyPathSource then
log_error("jm.tools.encrypt_file encrypt_path_all_files missing parameter sSpecifyPathSource")
return
end
if not sSpecifyPathTarget then
log_error("jm.tools.encrypt_file encrypt_path_all_files missing parameter sSpecifyPathTarget")
return
end
if not sPassWord then
log_error("jm.tools.encrypt_file encrypt_path_all_files missing parameter sPassWord")
return
end
if not tbFileType then
log_error("jm.tools.encrypt_file encrypt_path_all_files missing parameter tbFileType")
return
end
-- 搜索文件
local tbAllFilePath = {}
l_Api.get_all_files(sSpecifyPathSource,tbAllFilePath, tbFileType);
-- 路径长度
local nLenPathSource = string.len(sSpecifyPathSource)
-- 读取文件并加密
local sFileContext = nil
local sCiphertext = nil
local sSavePath = nil
local nFilePr
for _, sFilePath in ipairs(tbAllFilePath) do
nFilePr = assert(io.open(sFilePath), "Can't open faile :" .. sFilePath)
sFileContext = nFilePr:read("a")
nFilePr:close()
sCiphertext = cryption.encryption(sFileContext, sPassWord)
-- 将文件写入到指定路径中
-- 裁切 sFileName, 将 sSpecifyPathSource 剔除后,拼接到 sSpecifyPathTarget 后面
sSavePath = sSpecifyPathTarget .. string.sub(sFilePath, nLenPathSource+1)
l_Api.mkdir(sSpecifyPathTarget, string.sub(sFilePath, nLenPathSource+1))
-- 将文件写入到 sSavePath 中
nFilePr = assert(io.open(sSavePath, "w+"),"Can't create faile :" .. sSavePath)
assert(nFilePr:write(l_CiphertextHead), "Can't write faile :" .. sSavePath)
assert(nFilePr:write(sCiphertext), "Can't write faile :" .. sSavePath)
nFilePr:close()
-- break
end
end
--[[
@param sciphertext 密文
@return string 明文 or nil
]]
function M.decrypt(sCiphertext)
-- plaintext
-- log_error(":############# ", sFileName)
-- 测试解密
-- local temp = cryption.decryption(sCiphertext, sPassWord)
-- log_error("============= \n", temp)
end
function M.test()
-- local tbAllFilePath = {}
-- local tbFileType = {".lua"}
-- l_Api.get_all_files(lfs.currentdir(),tbAllFilePath, tbFileType);
-- log_info("#############", table.printT(tbAllFilePath))
M.encrypt_path_all_files(lfs.currentdir() .. "/jm", lfs.currentdir() .. "/jm/jm_encrypt", "dafasgsfdg",{".lua", ".pb"})
log_info("############## ", string.len(l_CiphertextHead))
-- l_Api.mkdir("/data/jm/jmserver", "/jm_encrypt/config/DockerTag.lua")
end
return M