在lua中计算一个字节数组/用户数据的crc16校验和

我正在使用lua编写Wireshark协议解析器。该协议包含一个crc16校验和,解析器应检查crc是否正确。

我已经在CRC16实现代码中找到了一个已经用lua封装好的C语言写的crc16实现代码。我已经成功编译并运行它(例如:crc16.compute("test"))。问题在于它需要一个字符串作为输入。从Wireshark中得到的缓冲区似乎是lua类型的“userdata”。所以当我这样做时:

crc16.compute(buffer(5, 19))

Lua会抱怨“compute的错误参数#1(需要字符串,得到userdata)”。

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

我并不一定需要使用这个实现。任何能接受userdata的crc16实现代码都可以完美解决问题。

点赞
用户1433331
用户1433331

你从wireshark中获得的缓冲区可以像这样用作ByteArray:

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

ByteArray有一个_toString函数,它将字节转换为以十六进制表示的字符串。因此,您可以这样调用crc函数:

crc16.compute(tostring(byte_array))

“表示为十六进制的字节”意味着具有位11111111的输入字节将转换为ASCII字符串FF。 ASCII字符串FF01000110 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_initcrc16_updatecrc16_finalize,而不是问题中链接的crc实现。问题在于您需要使用与生成crc时相同的多项式等。 Pycrc允许你根据需要生成crc函数。 我的数据包还包含一个crc32。 Pycrc也可以为crc32生成代码,因此对于crc32,它可以按相同的方式工作。

2017-04-06 09:31:53
用户5613578
用户5613578

Christopher K 概括了大部分正确的答案,但将十六进制值转换回字节似乎有点难以实现。但是,我因为在寻找类似的东西而开始着手研究了。

遗漏的诀窍是不仅可以使用 buffer:bytes() 函数调用,还可以使用

buffer:raw()

这提供了所需的准确性:一个可以直接解析的简单 TSTRING,无需进行 ASCII 转换,我想这可能会显著增加 C 代码的负载。

2021-04-16 19:06:27