diff --git a/src/main/java/org/traccar/helper/Checksum.java b/src/main/java/org/traccar/helper/Checksum.java index b070f8006..bf2501bda 100644 --- a/src/main/java/org/traccar/helper/Checksum.java +++ b/src/main/java/org/traccar/helper/Checksum.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2026 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,13 +17,26 @@ package org.traccar.helper; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.zip.CRC32; public final class Checksum { private Checksum() { } + public static final Algorithm CRC8_EGTS = new Algorithm(8, 0x31, 0xFF, false, false, 0x00); + public static final Algorithm CRC8_ROHC = new Algorithm(8, 0x07, 0xFF, true, true, 0x00); + public static final Algorithm CRC8_DALLAS = new Algorithm(8, 0x31, 0x00, true, true, 0x00); + + public static final Algorithm CRC16_IBM = new Algorithm(16, 0x8005, 0x0000, true, true, 0x0000); + public static final Algorithm CRC16_X25 = new Algorithm(16, 0x1021, 0xFFFF, true, true, 0xFFFF); + public static final Algorithm CRC16_MODBUS = new Algorithm(16, 0x8005, 0xFFFF, true, true, 0x0000); + public static final Algorithm CRC16_CCITT_FALSE = new Algorithm(16, 0x1021, 0xFFFF, false, false, 0x0000); + public static final Algorithm CRC16_KERMIT = new Algorithm(16, 0x1021, 0x0000, true, true, 0x0000); + public static final Algorithm CRC16_XMODEM = new Algorithm(16, 0x1021, 0x0000, false, false, 0x0000); + + public static final Algorithm CRC32_STANDARD = new Algorithm(32, 0x04C11DB7, 0xFFFFFFFF, true, true, 0xFFFFFFFF); + public static final Algorithm CRC32_MPEG2 = new Algorithm(32, 0x04C11DB7, 0xFFFFFFFF, false, false, 0x00000000); + public static class Algorithm { private final int poly; @@ -39,7 +52,13 @@ public final class Checksum { this.refIn = refIn; this.refOut = refOut; this.xorOut = xorOut; - this.table = bits == 8 ? initTable8() : initTable16(); + if (bits == 8) { + this.table = initTable8(); + } else if (bits == 16) { + this.table = initTable16(); + } else { + this.table = initTable32(); + } } private int[] initTable8() { @@ -76,6 +95,22 @@ public final class Checksum { return table; } + private int[] initTable32() { + int[] table = new int[256]; + for (int i = 0; i < 256; i++) { + int crc = i << 24; + for (int j = 0; j < 8; j++) { + if ((crc & 0x80000000) != 0) { + crc = (crc << 1) ^ poly; + } else { + crc <<= 1; + } + } + table[i] = crc; + } + return table; + } + } private static int reverse(int value, int bits) { @@ -117,23 +152,19 @@ public final class Checksum { return (crc ^ algorithm.xorOut) & 0xFFFF; } - public static final Algorithm CRC8_EGTS = new Algorithm(8, 0x31, 0xFF, false, false, 0x00); - public static final Algorithm CRC8_ROHC = new Algorithm(8, 0x07, 0xFF, true, true, 0x00); - public static final Algorithm CRC8_DALLAS = new Algorithm(8, 0x31, 0x00, true, true, 0x00); - - public static final Algorithm CRC16_IBM = new Algorithm(16, 0x8005, 0x0000, true, true, 0x0000); - public static final Algorithm CRC16_X25 = new Algorithm(16, 0x1021, 0xFFFF, true, true, 0xFFFF); - public static final Algorithm CRC16_MODBUS = new Algorithm(16, 0x8005, 0xFFFF, true, true, 0x0000); - public static final Algorithm CRC16_CCITT_FALSE = new Algorithm(16, 0x1021, 0xFFFF, false, false, 0x0000); - public static final Algorithm CRC16_KERMIT = new Algorithm(16, 0x1021, 0x0000, true, true, 0x0000); - public static final Algorithm CRC16_XMODEM = new Algorithm(16, 0x1021, 0x0000, false, false, 0x0000); - - public static int crc32(ByteBuffer buf) { - CRC32 checksum = new CRC32(); + public static int crc32(Algorithm algorithm, ByteBuffer buf) { + int crc = algorithm.init; while (buf.hasRemaining()) { - checksum.update(buf.get()); + int b = buf.get() & 0xFF; + if (algorithm.refIn) { + b = reverse(b, 8); + } + crc = (crc << 8) ^ algorithm.table[((crc >> 24) & 0xFF) ^ b]; } - return (int) checksum.getValue(); + if (algorithm.refOut) { + crc = reverse(crc, 32); + } + return crc ^ algorithm.xorOut; } public static int xor(ByteBuffer buf) { diff --git a/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java b/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java index 97ed7de96..ca7d63fd7 100644 --- a/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/ApelProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2026 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -70,7 +70,7 @@ public class ApelProtocolDecoder extends BaseProtocolDecoder { ByteBuf request = Unpooled.buffer(8); request.writeShortLE(type); request.writeShortLE(0); - request.writeIntLE(Checksum.crc32(request.nioBuffer(0, 4))); + request.writeIntLE(Checksum.crc32(Checksum.CRC32_STANDARD, request.nioBuffer(0, 4))); channel.writeAndFlush(new NetworkMessage(request, channel.remoteAddress())); } @@ -83,7 +83,7 @@ public class ApelProtocolDecoder extends BaseProtocolDecoder { request.writeShortLE(6); request.writeIntLE((int) lastIndex); request.writeShortLE(512); - request.writeIntLE(Checksum.crc32(request.nioBuffer(0, 10))); + request.writeIntLE(Checksum.crc32(Checksum.CRC32_STANDARD, request.nioBuffer(0, 10))); channel.writeAndFlush(new NetworkMessage(request, channel.remoteAddress())); } } diff --git a/src/test/java/org/traccar/helper/ChecksumTest.java b/src/test/java/org/traccar/helper/ChecksumTest.java index 51f62aba0..85a982280 100644 --- a/src/test/java/org/traccar/helper/ChecksumTest.java +++ b/src/test/java/org/traccar/helper/ChecksumTest.java @@ -31,6 +31,14 @@ public class ChecksumTest { assertEquals(0x31c3, Checksum.crc16(Checksum.CRC16_XMODEM, buf.nioBuffer())); } + @Test + public void testCrc32() { + ByteBuf buf = Unpooled.copiedBuffer("123456789", StandardCharsets.US_ASCII); + + assertEquals(0xcbf43926, Checksum.crc32(Checksum.CRC32_STANDARD, buf.nioBuffer())); + assertEquals(0x0376e6e7, Checksum.crc32(Checksum.CRC32_MPEG2, buf.nioBuffer())); + } + @Test public void testLuhn() { assertEquals(7, Checksum.luhn(12345678901234L));