在lua中计算bytearray / userdata的crc16

时间:2017-04-04 15:18:05

标签: c lua wireshark crc16 wireshark-dissector

我正在用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)

crc16 implementation中的

compute()如下所示:

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(),但这似乎返回了类似指针的东西。所以我需要长度的第二个参数,对吗?

我不一定需要使用此实现。接受用户数据的lua的任何crc16实现都可以完美地解决问题。

2 个答案:

答案 0 :(得分:0)

您从wireshark获得的缓冲区可以像ByteArray一样用作:

byte_array = Buffer(5,19):bytes();

ByteArray有一个_toString函数,可以将字节转换为以十六进制表示的字节的字符串表示形式。所以你可以像这样调用crc函数:

crc16.compute(tostring(byte_array))

'表示为十六进制的字节的表示'表示位11111111的输入字节将变为ASCII字符串FF。 ASCII字符串FF以位为01000110 01000110或以十六进制为46 46。这意味着你在C中获得的不是原始的bytearray。在计算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;
}

现在在compute函数中,我们遍历字符串表示,总是将两个字符组合成一个字节。

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_initcrc16_updatecrc16_finalize,而不是问题中链接的crc实现。问题是你需要使用与生成crc时相同的多项式等。 Pycrc允许您根据需要生成crc函数。 我的数据包还包含一个crc32。 Pycrc也可以为crc32生成代码,因此它对crc32的工作方式都一样。

答案 1 :(得分:0)

Christopher K 概述了大部分是正确的答案,但是将十六进制值转换回字节似乎有点像艰苦的工作,但这让我在寻找类似的东西时寻找。

遗漏的技巧是,除了使用 buffer:bytes() 调用函数外,您还可以调用

缓冲区:原始()

这正好提供了所需的东西:一个可以直接解析的简单 TSTRING,无需进行 ascii 转换,我想这会显着增加 C 代码的负载。

相关问题