IO-Link CRC32实现

IO-Link CRC32 implementation

目前我尝试从 IO-Link 为 Java [1] 中的 IODD 文件实现 CRC32 校验算法。在 IO-Link 中,每个传感器都使用 IODD xml 文件 [2] 进行描述。该文件包含带有 crc 代码的戳记标签。我这里的问题是算法只使用无符号整数而 Java 不使用这种类型。还有办法实现吗?

我还使用JetBrains dotPeek 程序反编译了IODDChecker(最新版本)。 CRC 逻辑在文件 clsCRC.cs 中。在文件的末尾,我找到了计算 CRC 的方法“CRC32”。问题是他们使用其他整数(无符号整数)来查找-table。一个有趣的事实是,IODD 检查器 (crc32_octetwise) 中的算法与规范中描述的算法略有不同。

希望你能帮助我:)

我测试的内容:

程序:

  1. 程序将 IODD 读取为 String/byte 数组
  2. 从 String/byte 数组
  3. 的 Stamp-Tag 中删除 CRC 值
  4. 从 string/byte 数组创建 CRC32
  5. 在测试IODD中你可以找到CRC 1195433981,它应该等于算法的输出

算法:
有两种算法。第一个是按位的,第二个是八位字节的,使用查找-table,您可以在此处找到 [2].

uint32_t crc32_bitwise(char *data, size_t length, uint32_t previousCrc32 = 1)
{
    uint32_t crc = ~previousCrc32;
    int j;
    const uint8_t* current = (const uint8_t*) data;
    while (length-- > 0)
    {
        crc ^= *current++;
        for (j = 0; j < 8; j++)
        {
            crc = (crc >> 1) ^ (-(int32_t)(crc & 1) & 0xEB31D82E);
        }
    }
    return ~crc;
}
uint32_t crc32_octetwise(uint8_t const * current, uint32_t length, uint32_t previousCrc32 = 1, const uint32_t crc32Lookup[256])
{
    uint32_t crc = ~previousCrc32;
    while (length-- > 0)
        crc = (crc >> 8) ^ crc32Lookup[(crc & 0xFF) ^ *current++];
    return ~crc;
}

[1] https://io-link.com/share/Downloads/Profiles/IOL-Profile_Firmware-Update_V11_10082_Sep19.zip
[2] https://ioddfinder.io-link.com/productvariants/search/11765
[3] Yet another Java CRC32 implementation related issue

更新 1

我忘了补充一点,我目前收到的 CRC 代码是 1120211745,但 1195433981 是正确的代码。

更新 2

以下代码是我实施的。大数组是查找 tables。第一个 int 数组是 [1] 中的 table,第二个是反编译源中的数组。原来是标记为无符号的 int 数字(例如 1996959894U)。

private static final int[] numArr1 = new int[] {
            0x00000000, 0x9695C4CA, 0xFB4839C9, 0x6DDDFD03, 0x20F3C3CF, 0xB6660705, 0xDBBBFA06, 0x4D2E3ECC, 0x41E7879E, 0xD7724354, 0xBAAFBE57, 0x2C3A7A9D, 0x61144451, 0xF781809B, 0x9A5C7D98, 0x0CC9B952, 0x83CF0F3C, 0x155ACBF6, 0x788736F5, 0xEE12F23F, 0xA33CCCF3, 0x35A90839, 0x5874F53A, 0xCEE131F0, 0xC22888A2, 0x54BD4C68, 0x3960B16B, 0xAFF575A1, 0xE2DB4B6D, 0x744E8FA7, 0x199372A4, 0x8F06B66E, 0xD1FDAE25, 0x47686AEF, 0x2AB597EC, 0xBC205326, 0xF10E6DEA, 0x679BA920, 0x0A465423, 0x9CD390E9, 0x901A29BB, 0x068FED71, 0x6B521072, 0xFDC7D4B8, 0xB0E9EA74, 0x267C2EBE, 0x4BA1D3BD, 0xDD341777, 0x5232A119, 0xC4A765D3, 0xA97A98D0, 0x3FEF5C1A, 0x72C162D6, 0xE454A61C, 0x89895B1F, 0x1F1C9FD5, 0x13D52687, 0x8540E24D, 0xE89D1F4E, 0x7E08DB84, 0x3326E548, 0xA5B32182, 0xC86EDC81, 0x5EFB184B, 0x7598EC17, 0xE30D28DD, 0x8ED0D5DE, 0x18451114, 0x556B2FD8, 0xC3FEEB12, 0xAE231611, 0x38B6D2DB, 0x347F6B89, 0xA2EAAF43, 0xCF375240, 0x59A2968A, 0x148CA846, 0x82196C8C, 0xEFC4918F, 0x79515545, 0xF657E32B, 0x60C227E1, 0x0D1FDAE2, 0x9B8A1E28, 0xD6A420E4, 0x4031E42E, 0x2DEC192D, 0xBB79DDE7, 0xB7B064B5, 0x2125A07F, 0x4CF85D7C, 0xDA6D99B6, 0x9743A77A, 0x01D663B0, 0x6C0B9EB3, 0xFA9E5A79, 0xA4654232, 0x32F086F8, 0x5F2D7BFB, 0xC9B8BF31, 0x849681FD, 0x12034537, 0x7FDEB834, 0xE94B7CFE, 0xE582C5AC, 0x73170166, 0x1ECAFC65, 0x885F38AF, 0xC5710663, 0x53E4C2A9, 0x3E393FAA, 0xA8ACFB60, 0x27AA4D0E, 0xB13F89C4, 0xDCE274C7, 0x4A77B00D, 0x07598EC1, 0x91CC4A0B, 0xFC11B708, 0x6A8473C2, 0x664DCA90, 0xF0D80E5A, 0x9D05F359, 0x0B903793, 0x46BE095F, 0xD02BCD95, 0xBDF63096, 0x2B63F45C, 0xEB31D82E, 0x7DA41CE4, 0x1079E1E7, 0x86EC252D, 0xCBC21BE1, 0x5D57DF2B, 0x308A2228, 0xA61FE6E2, 0xAAD65FB0, 0x3C439B7A, 0x519E6679, 0xC70BA2B3, 0x8A259C7F, 0x1CB058B5, 0x716DA5B6, 0xE7F8617C, 0x68FED712, 0xFE6B13D8, 0x93B6EEDB, 0x05232A11, 0x480D14DD, 0xDE98D017, 0xB3452D14, 0x25D0E9DE, 0x2919508C, 0xBF8C9446, 0xD2516945, 0x44C4AD8F, 0x09EA9343, 0x9F7F5789, 0xF2A2AA8A, 0x64376E40, 0x3ACC760B, 0xAC59B2C1, 0xC1844FC2, 0x57118B08, 0x1A3FB5C4, 0x8CAA710E, 0xE1778C0D, 0x77E248C7, 0x7B2BF195, 0xEDBE355F, 0x8063C85C, 0x16F60C96, 0x5BD8325A, 0xCD4DF690, 0xA0900B93, 0x3605CF59, 0xB9037937, 0x2F96BDFD, 0x424B40FE, 0xD4DE8434, 0x99F0BAF8, 0x0F657E32, 0x62B88331, 0xF42D47FB, 0xF8E4FEA9, 0x6E713A63, 0x03ACC760, 0x953903AA, 0xD8173D66, 0x4E82F9AC, 0x235F04AF, 0xB5CAC065, 0x9EA93439, 0x083CF0F3, 0x65E10DF0, 0xF374C93A, 0xBE5AF7F6, 0x28CF333C, 0x4512CE3F, 0xD3870AF5, 0xDF4EB3A7, 0x49DB776D, 0x24068A6E, 0xB2934EA4, 0xFFBD7068, 0x6928B4A2, 0x04F549A1, 0x92608D6B, 0x1D663B05, 0x8BF3FFCF, 0xE62E02CC, 0x70BBC606, 0x3D95F8CA, 0xAB003C00, 0xC6DDC103, 0x504805C9, 0x5C81BC9B, 0xCA147851, 0xA7C98552, 0x315C4198, 0x7C727F54, 0xEAE7BB9E, 0x873A469D, 0x11AF8257, 0x4F549A1C, 0xD9C15ED6, 0xB41CA3D5, 0x2289671F, 0x6FA759D3, 0xF9329D19, 0x94EF601A, 0x027AA4D0, 0x0EB31D82, 0x9826D948, 0xF5FB244B, 0x636EE081, 0x2E40DE4D, 0xB8D51A87, 0xD508E784, 0x439D234E, 0xCC9B9520, 0x5A0E51EA, 0x37D3ACE9, 0xA1466823, 0xEC6856EF, 0x7AFD9225, 0x17206F26, 0x81B5ABEC, 0x8D7C12BE, 0x1BE9D674, 0x76342B77, 0xE0A1EFBD, 0xAD8FD171, 0x3B1A15BB, 0x56C7E8B8, 0xC0522C72
    };

private static final long[] numArr2 = new long[] {
            0L, 1996959894L, 3993919788L, 2567524794L, 124634137L, 1886057615L, 3915621685L, 2657392035L, 249268274L, 2044508324L, 3772115230L, 2547177864L, 162941995L, 2125561021L, 3887607047L, 2428444049L, 498536548L, 1789927666L, 4089016648L, 2227061214L, 450548861L, 1843258603L, 4107580753L, 2211677639L, 325883990L, 1684777152L, 4251122042L, 2321926636L, 335633487L, 1661365465L, 4195302755L, 2366115317L, 997073096L, 1281953886L, 3579855332L, 2724688242L, 1006888145L, 1258607687L, 3524101629L, 2768942443L, 901097722L, 1119000684L, 3686517206L, 2898065728L, 853044451L, 1172266101L, 3705015759L, 2882616665L, 651767980L, 1373503546L, 3369554304L, 3218104598L, 565507253L, 1454621731L, 3485111705L, 3099436303L, 671266974L, 1594198024L, 3322730930L, 2970347812L, 795835527L, 1483230225L, 3244367275L, 3060149565L, 1994146192L, 31158534L, 2563907772L, 4023717930L, 1907459465L, 112637215L, 2680153253L, 3904427059L, 2013776290L, 251722036L, 2517215374L, 3775830040L, 2137656763L, 141376813L, 2439277719L, 3865271297L, 1802195444L, 476864866L, 2238001368L, 4066508878L, 1812370925L, 453092731L, 2181625025L, 4111451223L, 1706088902L, 314042704L, 2344532202L, 4240017532L, 1658658271L, 366619977L, 2362670323L, 4224994405L, 1303535960L, 984961486L, 2747007092L, 3569037538L, 1256170817L, 1037604311L, 2765210733L, 3554079995L, 1131014506L, 879679996L, 2909243462L, 3663771856L, 1141124467L, 855842277L, 2852801631L, 3708648649L, 1342533948L, 654459306L, 3188396048L, 3373015174L, 1466479909L, 544179635L, 3110523913L, 3462522015L, 1591671054L, 702138776L, 2966460450L, 3352799412L, 1504918807L, 783551873L, 3082640443L, 3233442989L, 3988292384L, 2596254646L, 62317068L, 1957810842L, 3939845945L, 2647816111L, 81470997L, 1943803523L, 3814918930L, 2489596804L, 225274430L, 2053790376L, 3826175755L, 2466906013L, 167816743L, 2097651377L, 4027552580L, 2265490386L, 503444072L, 1762050814L, 4150417245L, 2154129355L, 426522225L, 1852507879L, 4275313526L, 2312317920L, 282753626L, 1742555852L, 4189708143L, 2394877945L, 397917763L, 1622183637L, 3604390888L, 2714866558L, 953729732L, 1340076626L, 3518719985L, 2797360999L, 1068828381L, 1219638859L, 3624741850L, 2936675148L, 906185462L, 1090812512L, 3747672003L, 2825379669L, 829329135L, 1181335161L, 3412177804L, 3160834842L, 628085408L, 1382605366L, 3423369109L, 3138078467L, 570562233L, 1426400815L, 3317316542L, 2998733608L, 733239954L, 1555261956L, 3268935591L, 3050360625L, 752459403L, 1541320221L, 2607071920L, 3965973030L, 1969922972L, 40735498L, 2617837225L, 3943577151L, 1913087877L, 83908371L, 2512341634L, 3803740692L, 2075208622L, 213261112L, 2463272603L, 3855990285L, 2094854071L, 198958881L, 2262029012L, 4057260610L, 1759359992L, 534414190L, 2176718541L, 4139329115L, 1873836001L, 414664567L, 2282248934L, 4279200368L, 1711684554L, 285281116L, 2405801727L, 4167216745L, 1634467795L, 376229701L, 2685067896L, 3608007406L, 1308918612L, 956543938L, 2808555105L, 3495958263L, 1231636301L, 1047427035L, 2932959818L, 3654703836L, 1088359270L, 936918000L, 2847714899L, 3736837829L, 1202900863L, 817233897L, 3183342108L, 3401237130L, 1404277552L, 615818150L, 3134207493L, 3453421203L, 1423857449L, 601450431L, 3009837614L, 3294710456L, 1567103746L, 711928724L, 3020668471L, 3272380065L, 1510334235L, 755167117L
    };

使用来自 java.util.zip 的 CRC32 进行测试:

public static String crc32(byte[] data) {
    Checksum c = new CRC32();

    c.update(1);
    c.update(data);

    return String.valueOf(Long.parseLong(Long.toHexString(c.getValue()), 16));    // 1544046132
}

来自[3]的解决方案

public static String crc32(byte[] data){
    int crc = Integer.MAX_VALUE;

    for (byte b : data)
        crc = numArr[(crc & 0xff) ^ (b & 0xff) & 255] ^ (crc >>> 8);

    crc = ~crc; // flip bit/sign

    return String.valueOf(Long.parseLong(Integer.toHexString(crc), 16));    // 1120211745
}

这个实现用的是Guava,是我直接改造的。我还尝试了 BigInteger,位操作来强制执行无符号并使用字节数组而不是 int 或 long。

public static String crc32(byte[] data) {
    long num = UnsignedInteger.MAX_VALUE.longValue();

    for (byte aByte : data)
        num = numArr2[(Integer.parseUnsignedInt(Long.toUnsignedString(num)) ^ aByte) & 255] ^ (num >>> 8);

    num ^= UnsignedInteger.MAX_VALUE.longValue();

    return String.valueOf(num);     // 2128031166
}

更新 3

我尝试使用 BigInteger 重新开始,现在结果更接近了。 CRC 为 1190225612(预期:1195433981)。

public static String crc32(byte[] bytes) {
    BigInteger num = BigInteger.valueOf(0xffffffffL);

    for (byte aByte: bytes)
        num = BigInteger.valueOf(numArr[num.xor(BigInteger.valueOf(aByte)).and(BigInteger.valueOf(numArr.length - 1)).intValue()]).xor((num.shiftRight(8)));

    num = num.xor(BigInteger.valueOf(0xffffffffL));

    System.out.println("1195433981");
    return String.valueOf(~num.intValue());
}

更新 4

更新程序说明。不会删除带有 Stamp 标记的整行,而只会删除 CRC 属性中的值。

您的初始 CRC 错误。它是 1。来自您链接的文档:

The seed value shall be "1" (see previousCrc32 = 1 in Figure B.1 and Figure B.2).

然后在循环之前将该值反转,因此此时您的“num”应该是 0xfffffffe

numArr1是正确的。我不知道你的numArr2来自哪里。

你只需要这个,第一个参数是 1:

static private int crc32iodd(int crc, byte[] data){
    crc = ~crc;
    for (byte b : data)
        crc = numArr1[(crc ^ b) & 0xff] ^ (crc >>> 8);
    return ~crc;
}

因为 Java 没有 unsigned int,有一半的时间你的结果是负数。没关系,因为它与无符号结果完全相同的 32 位,只是打印方式不同。

答案没有“更近”的感觉。你想要的和你得到的之间的整数差在 CRC 的世界里没有意义,因为它们不是整数计算。

更新:

仔细查看您在问题中输入的链接和 CRC 参考代码,您似乎为实际需要的 CRC 引用了完全错误的文档。您引用了用于固件更新的 BLOB 的 CRC,它是 而不是 用于验证 XML 文件的 CRC。 This document 提供用于 XML 文件的 CRC 规范,作为 ITU-T 建议 V.42 中的 32 位 CRC。这是使用不同多项式和不同初始值的不同 CRC。它实际上是 zip 使用的标准 CRC-32,并且在 Java 中可用 java.util.zip.CRC32。您不需要编写任何 CRC 代码。就用那个吧。

该文档还指出但没有详细说明在计算 CRC 之前对 XML 输入的特殊处理。您将需要做更多的研究,以准确找出 XML 文件中的 CRC 计算依据,以及它是如何预处理的。 This package 有一个描述,指出相关语言 xml 在每个 CRC 计算之前将主要 xml 的 CRC 附加到末尾。然而,CRC 是如何附加的并不清楚。

这次请您充分研究和验证,然后再带着关于如何实施错误识别的CRC的问题来这里。

为了完整起见。

你是对的。我可以用java.util.zip.CRC32。我认为问题在于我在实施测试开始时尝试使用整个 xml 文件,因此我认为 PDF 中的描述是错误的。

解决方法如下: 如果你有一个 IODD XML 文件,那么你必须删除 stamp-tag 中的 crc 值。随后,如果尚未完成,则将没有 crc 值的文件内容转换为字节数组。现在您可以使用这两个函数之一:

java.util.zip.CRC32

一起实施
public boolean isValid() {
    CRC32 m = new CRC32();
    m.update(file);
    long x = 1195433981L;
    
    return (m.getValue() == x);
}

手动实现(table根据站点https://rosettacode.org/wiki/CRC-32#Lingo or https://web.mit.edu/freebsd/head/sys/libkern/crc32.c

public class Crc32 {
    private static final long[] numArr2 = new long[] {
            0L, 1996959894L, 3993919788L, 2567524794L, 124634137L, 1886057615L, 3915621685L, 2657392035L, 249268274L, 2044508324L, 3772115230L, 2547177864L, 162941995L, 2125561021L, 3887607047L, 2428444049L, 498536548L, 1789927666L, 4089016648L, 2227061214L, 450548861L, 1843258603L, 4107580753L, 2211677639L, 325883990L, 1684777152L, 4251122042L, 2321926636L, 335633487L, 1661365465L, 4195302755L, 2366115317L, 997073096L, 1281953886L, 3579855332L, 2724688242L, 1006888145L, 1258607687L, 3524101629L, 2768942443L, 901097722L, 1119000684L, 3686517206L, 2898065728L, 853044451L, 1172266101L, 3705015759L, 2882616665L, 651767980L, 1373503546L, 3369554304L, 3218104598L, 565507253L, 1454621731L, 3485111705L, 3099436303L, 671266974L, 1594198024L, 3322730930L, 2970347812L, 795835527L, 1483230225L, 3244367275L, 3060149565L, 1994146192L, 31158534L, 2563907772L, 4023717930L, 1907459465L, 112637215L, 2680153253L, 3904427059L, 2013776290L, 251722036L, 2517215374L, 3775830040L, 2137656763L, 141376813L, 2439277719L, 3865271297L, 1802195444L, 476864866L, 2238001368L, 4066508878L, 1812370925L, 453092731L, 2181625025L, 4111451223L, 1706088902L, 314042704L, 2344532202L, 4240017532L, 1658658271L, 366619977L, 2362670323L, 4224994405L, 1303535960L, 984961486L, 2747007092L, 3569037538L, 1256170817L, 1037604311L, 2765210733L, 3554079995L, 1131014506L, 879679996L, 2909243462L, 3663771856L, 1141124467L, 855842277L, 2852801631L, 3708648649L, 1342533948L, 654459306L, 3188396048L, 3373015174L, 1466479909L, 544179635L, 3110523913L, 3462522015L, 1591671054L, 702138776L, 2966460450L, 3352799412L, 1504918807L, 783551873L, 3082640443L, 3233442989L, 3988292384L, 2596254646L, 62317068L, 1957810842L, 3939845945L, 2647816111L, 81470997L, 1943803523L, 3814918930L, 2489596804L, 225274430L, 2053790376L, 3826175755L, 2466906013L, 167816743L, 2097651377L, 4027552580L, 2265490386L, 503444072L, 1762050814L, 4150417245L, 2154129355L, 426522225L, 1852507879L, 4275313526L, 2312317920L, 282753626L, 1742555852L, 4189708143L, 2394877945L, 397917763L, 1622183637L, 3604390888L, 2714866558L, 953729732L, 1340076626L, 3518719985L, 2797360999L, 1068828381L, 1219638859L, 3624741850L, 2936675148L, 906185462L, 1090812512L, 3747672003L, 2825379669L, 829329135L, 1181335161L, 3412177804L, 3160834842L, 628085408L, 1382605366L, 3423369109L, 3138078467L, 570562233L, 1426400815L, 3317316542L, 2998733608L, 733239954L, 1555261956L, 3268935591L, 3050360625L, 752459403L, 1541320221L, 2607071920L, 3965973030L, 1969922972L, 40735498L, 2617837225L, 3943577151L, 1913087877L, 83908371L, 2512341634L, 3803740692L, 2075208622L, 213261112L, 2463272603L, 3855990285L, 2094854071L, 198958881L, 2262029012L, 4057260610L, 1759359992L, 534414190L, 2176718541L, 4139329115L, 1873836001L, 414664567L, 2282248934L, 4279200368L, 1711684554L, 285281116L, 2405801727L, 4167216745L, 1634467795L, 376229701L, 2685067896L, 3608007406L, 1308918612L, 956543938L, 2808555105L, 3495958263L, 1231636301L, 1047427035L, 2932959818L, 3654703836L, 1088359270L, 936918000L, 2847714899L, 3736837829L, 1202900863L, 817233897L, 3183342108L, 3401237130L, 1404277552L, 615818150L, 3134207493L, 3453421203L, 1423857449L, 601450431L, 3009837614L, 3294710456L, 1567103746L, 711928724L, 3020668471L, 3272380065L, 1510334235L, 755167117L
    };

    private static long crc32(byte[] data){
        long crc = 0xFFFFFFFFL;

        for (byte b : data)
            crc = numArr2[(int)(crc ^ b) & 0xff] ^ (crc >>> 8);

        return crc ^ 0xFFFFFFFFL;
    }
    
    public static boolean isValid(byte[] data, long checkCrc) {
        long crc = crc32(data);
        
        return (checkCrc == crc);
    }
}