C EVP_更新永不返回
我正在重写LuaCrypto,使其在Lua5.3上运行并支持SSL 1.1.0。(它的原始代码在Lua5.1上运行,支持SSL,最高可达1.0)。C EVP_更新永不返回,c,lua,openssl,C,Lua,Openssl,我正在重写LuaCrypto,使其在Lua5.3上运行并支持SSL 1.1.0。(它的原始代码在Lua5.1上运行,支持SSL,最高可达1.0)。 LuaCrypto和Lua5.3之间不兼容的主要原因是加载机制,该机制经历了重大修改,我通过替换与加载库相关的所有函数使其正常工作。 LuaCrypto和SSL 1.1.0之间不兼容的主要原因是,现在SSL结构(特别是EVP和HMAC)是不透明的,编译器不再知道这些结构的内部或大小。 不幸的是,LibCrypto依赖于知道这些结构的大小,将它们作为用
LuaCrypto和Lua5.3之间不兼容的主要原因是加载机制,该机制经历了重大修改,我通过替换与加载库相关的所有函数使其正常工作。
LuaCrypto和SSL 1.1.0之间不兼容的主要原因是,现在SSL结构(特别是EVP和HMAC)是不透明的,编译器不再知道这些结构的内部或大小。
不幸的是,LibCrypto依赖于知道这些结构的大小,将它们作为用户数据加载到Lua状态。然后,显而易见的解决方案是重写库,使其将EVP和HMAC结构加载为lightuserdata,并重写垃圾收集器元方法以调用SSL free/destroy/Anwhere,以便在不再需要这些结构时从这些结构中删除内存。
我做到了这一点,只要我在一步中运行加密/解密/摘要,这一切都很有趣。每当我尝试通过EVP_UPDATE()函数递增地使用EVP时,调用此函数时机器就会冻结,但如果我尝试在一个步骤中运行解密,则不会冻结。
以下是违规代码:
static HANDLER_EVP *evp_pget(lua_State *L, int i)
{
if (luaL_checkudata(L, i, LUACRYPTO_EVPNAME) == NULL)
luaL_typerror(L, i, LUACRYPTO_EVPNAME);
return lua_touserdata(L, i);
}
void evp_pnew(lua_State *L, HANDLER_EVP *c)
{
lua_pushlightuserdata(L, c);
luaL_getmetatable(L, LUACRYPTO_EVPNAME);
lua_setmetatable(L, -2);
}
static int evp_fnew(lua_State *L)
{
HANDLER_EVP *c = NULL;
const char *s = luaL_checkstring(L, 1);
DIGEST_TYPE type = DIGEST_BY_NAME(s);
if (IS_DIGEST_INVALID(type)) {
luaL_argerror(L, 1, "invalid digest type");
return 0;
}
static int evp_update(lua_State *L)
{
HANDLER_EVP *c = evp_pget(L, 1);
size_t s_len;
const char *s = luaL_checklstring(L, 2, &s_len);
dumpStack(L);
debug(L, "c=%p, s=\"%s\", s_len=%d", c, s, s_len);
EVP_UPDATE(c, s, s_len); // HERE IS THE PROBLEM
debug(L, "I AM HERE"); // never run
lua_settop(L, 1);
return 1;
}
这是Lua测试:
for i, t in ipairs({"sha1", "md5", "sha1", "hmac"}) do
print("testing " .. t)
local d
if (t == "hmac") then
d = hmac.new("sha1", "luacrypto")
else
d = evp.new(t)
end
assert(io.input(F))
print("all", d:digest(io.read("*all")), F, t)
d:reset()
assert(io.input(F))
while true do
local c = io.read(1)
if c == nil then break end
d:update(c)
end
print("loop", d:digest(), F, t)
if (t ~= "hmac") then
print("again", d:digest(), F, t)
assert(io.input(F))
print("alone", hmac.digest("sha1", io.read("*all"), "luacrypto"), F, t);
else
assert(io.input(F))
print("alone", hmac.digest("sha1", io.read("*all"), "luacrypto"), F, t);
end
assert(io.input(F))
d:reset()
while true do
local c = io.read(math.random(1, 16))
if c == nil then break end
d:update(c)
end
report("reset", d:digest(d), F, t)
report("known", _G[t .. "_KNOWN"], F, t)
print("")
end
这是输出:
testing sha1
TAG:lua_print LINE:141
c=0xc14a8
TAG:lua_print LINE:141
all d6ed6e26ebeb37ba0792ec75a3d0b4dcec279d25 /mtd0/message sha1
TAG:lua_print LINE:141
estou aqui
TAG:lua_print LINE:141
1: userdata
2: "T"
TAG:lua_print LINE:141
c=0xc14a8, s="T", s_len=1
我缺少什么?不能为light userdata设置元表
您需要将每个SSL结构指针放入一个(重)用户数据中。好的,伙计们,我得到了这个。问题似乎不在原来的位置。
显然,reset()函数因某种原因而存在缺陷。
这是我为重置所做的:
static int evp_reset(lua_State *L)
{
#ifdef CRYPTO_OPENSSL
EVP_MD_CTX_reset(c);
#elif CRYPTO_GCRYPT
gcry_md_reset(*c);
#endif
return 0;
}
出于某种原因,EVP\u MD\u CTX\u reset()
没有按照文档中的说明执行操作,也没有清理结构。因此,我尝试通过以下方式手动执行此操作:
static int evp_reset(lua_State *L)
{
HANDLER_EVP *c = evp_pget(L, 1);
#ifdef CRYPTO_OPENSSL
const EVP_MD *t = EVP_MD_CTX_md(c);
//EVP_MD_CTX_reset(c);
EVP_MD_CTX_init(c);
EVP_DigestInit_ex(c, t, NULL);
#elif CRYPTO_GCRYPT
gcry_md_reset(*c);
#endif
return 0;
}
这消除了故障。这似乎是SSL库中的一个bug 我为light userdata设置元表没有问题。也许这是旧版本lua的一个限制。您已经为所有light userdata值设置了相同的meltable。只有表和重userdata值可以有单独的元表。这没有意义。。。轻用户数据比任何其他lua类型更需要_gc元方法,因为它需要在C端显式地进行dellocation,而重用户数据在丢失lua状态的所有引用时会自动进行dellocation。如果这是Lua开发人员的一个深思熟虑的决定,那么这是一个非常糟糕的决定。。。但不管怎样,正如你所指出的,总有办法解决的。