在 lua 中计算字节数组/用户数据的 crc16
Compute the crc16 of a bytearray / userdata in lua
我正在 lua 中编写 Wireshark 协议解析器。它解析的协议包含一个 crc16 校验和。解剖者应该检查crc是否正确。
我找到了一个用 C 语言编写的 crc16 实现,其中包含 lua 包装代码 here。我已经成功编译它并且运行它(例如crc16.compute("test")
)。问题是它需要一个字符串作为输入。从 wireshark,我得到一个似乎是 lua 类型 userdata
的缓冲区。所以当我这样做时
crc16.compute(buffer(5, 19))
Lua抱怨bad argument #1 to compute (string expected, got userdata)
.
compute()
在 crc16 implementation 中看起来像这样:
static int compute(lua_State *L)
{
const char *data;
size_t len = 0;
unsigned short r, crc = 0;
data = luaL_checklstring(L, 1, &len);
for ( ; len > 0; len--)
{
r = (unsigned short)(crc >> 8);
crc <<= 8;
crc ^= crc_table[r ^ *data];
data ++;
}
lua_pushinteger(L, crc);
return 1;
}
似乎luaL_checklstring
失败了。所以我想我要么需要将输入转换为 lua 字符串,我不确定它是否有效,因为并非我输入的所有字节都是可打印字符。或者我需要调整上面的代码,以便它接受 userdata 类型的输入。我找到了 lua_touserdata()
,但这似乎是 return 类似指针的东西。所以我需要第二个长度参数,对吗?
我不一定需要使用这个实现。 lua 接受用户数据的任何 crc16 实现都可以完美解决问题。
您从 wireshark 获得的缓冲区可以像这样用作 ByteArray:
byte_array = Buffer(5,19):bytes();
ByteArray 有一个 _toString
函数,可以将字节转换为以十六进制表示的字节的字符串表示形式。所以你可以这样调用crc函数:
crc16.compute(tostring(byte_array))
'Representation of the bytes represented as hex' 表示带有位 11111111
的输入字节将变成 ASCII 字符串 FF
。 ASCII 字符串 FF
是 01000110 01000110
位或 46 46
十六进制。这意味着你在 C 中得到的不是原始字节数组。在计算 crc 之前,您需要将 ascii 表示解码回原始字节,否则我们显然会得到不同的 crc。
首先,此函数将包含一个 ascii 十六进制字符的单个字符 c
转换回它表示的值:
static char ascii2char(char c) {
c = tolower(c);
if(c >= '0' && c <= '9')
return c - '0';
else if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
}
现在在计算函数中,我们遍历字符串表示,始终将两个字符组合成一个字节。
int compute(lua_State *L) {
size_t len;
const char * str = lua_tolstring(L, 1, &len);
uint8_t * data = (uint8_t *) malloc(len/2);
for(int n=0; n<len/2; n++) {
data[n] = ascii2char(str[2*n]) << 4;
data[n] |= ascii2char(str[2*n+1]);
}
crc16_t crc = crc16_init();
crc = crc16_update(crc, data, len/2);
crc = crc16_finalize(crc);
lua_pushinteger(L, crc);
free(data);
return 1;
}
在此示例中,我使用了使用 pycrc 生成的 crc 函数 crc16_init
、crc16_update
和 crc16_finalize
,而不是问题中链接的 crc 实现。问题是您需要使用与生成 crc 时相同的多项式等。 Pycrc 允许您根据需要生成 crc 函数。
我的数据包也包含一个 crc32。 Pycrc 也可以为 crc32 生成代码,所以它对 crc32 的工作方式完全相同。
Christopher K 概述了大部分是正确的答案,但将十六进制值转换回字节似乎有点困难,但这让我在搜索类似内容时寻找。
错过的技巧是,除了使用 buffer:bytes() 调用函数外,您还可以调用
缓冲区:原始()
这提供了所需要的东西:一个简单的 TSTRING,可以直接解析而不需要进行 ascii 转换,我想这会显着增加 C 代码的负载。
我正在 lua 中编写 Wireshark 协议解析器。它解析的协议包含一个 crc16 校验和。解剖者应该检查crc是否正确。
我找到了一个用 C 语言编写的 crc16 实现,其中包含 lua 包装代码 here。我已经成功编译它并且运行它(例如crc16.compute("test")
)。问题是它需要一个字符串作为输入。从 wireshark,我得到一个似乎是 lua 类型 userdata
的缓冲区。所以当我这样做时
crc16.compute(buffer(5, 19))
Lua抱怨bad argument #1 to compute (string expected, got userdata)
.
compute()
在 crc16 implementation 中看起来像这样:
static int compute(lua_State *L)
{
const char *data;
size_t len = 0;
unsigned short r, crc = 0;
data = luaL_checklstring(L, 1, &len);
for ( ; len > 0; len--)
{
r = (unsigned short)(crc >> 8);
crc <<= 8;
crc ^= crc_table[r ^ *data];
data ++;
}
lua_pushinteger(L, crc);
return 1;
}
似乎luaL_checklstring
失败了。所以我想我要么需要将输入转换为 lua 字符串,我不确定它是否有效,因为并非我输入的所有字节都是可打印字符。或者我需要调整上面的代码,以便它接受 userdata 类型的输入。我找到了 lua_touserdata()
,但这似乎是 return 类似指针的东西。所以我需要第二个长度参数,对吗?
我不一定需要使用这个实现。 lua 接受用户数据的任何 crc16 实现都可以完美解决问题。
您从 wireshark 获得的缓冲区可以像这样用作 ByteArray:
byte_array = Buffer(5,19):bytes();
ByteArray 有一个 _toString
函数,可以将字节转换为以十六进制表示的字节的字符串表示形式。所以你可以这样调用crc函数:
crc16.compute(tostring(byte_array))
'Representation of the bytes represented as hex' 表示带有位 11111111
的输入字节将变成 ASCII 字符串 FF
。 ASCII 字符串 FF
是 01000110 01000110
位或 46 46
十六进制。这意味着你在 C 中得到的不是原始字节数组。在计算 crc 之前,您需要将 ascii 表示解码回原始字节,否则我们显然会得到不同的 crc。
首先,此函数将包含一个 ascii 十六进制字符的单个字符 c
转换回它表示的值:
static char ascii2char(char c) {
c = tolower(c);
if(c >= '0' && c <= '9')
return c - '0';
else if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
}
现在在计算函数中,我们遍历字符串表示,始终将两个字符组合成一个字节。
int compute(lua_State *L) {
size_t len;
const char * str = lua_tolstring(L, 1, &len);
uint8_t * data = (uint8_t *) malloc(len/2);
for(int n=0; n<len/2; n++) {
data[n] = ascii2char(str[2*n]) << 4;
data[n] |= ascii2char(str[2*n+1]);
}
crc16_t crc = crc16_init();
crc = crc16_update(crc, data, len/2);
crc = crc16_finalize(crc);
lua_pushinteger(L, crc);
free(data);
return 1;
}
在此示例中,我使用了使用 pycrc 生成的 crc 函数 crc16_init
、crc16_update
和 crc16_finalize
,而不是问题中链接的 crc 实现。问题是您需要使用与生成 crc 时相同的多项式等。 Pycrc 允许您根据需要生成 crc 函数。
我的数据包也包含一个 crc32。 Pycrc 也可以为 crc32 生成代码,所以它对 crc32 的工作方式完全相同。
Christopher K 概述了大部分是正确的答案,但将十六进制值转换回字节似乎有点困难,但这让我在搜索类似内容时寻找。
错过的技巧是,除了使用 buffer:bytes() 调用函数外,您还可以调用
缓冲区:原始()
这提供了所需要的东西:一个简单的 TSTRING,可以直接解析而不需要进行 ascii 转换,我想这会显着增加 C 代码的负载。