Skip to content
Terug naar blog
Tutorials

CRC-16-varianten: waarom MODBUS, CCITT en XMODEM verschillen

Dezelfde bytes, vier verschillende CRC-16-uitkomsten. Ontdek online hoe poly, init, refin, refout en xorout MODBUS scheiden van CCITT-FALSE en XMODEM.

13 min leestijd

Waarom dezelfde bytes vier verschillende CRC-16-uitkomsten geven

CRC-16 is de naam van een familie, niet van een algoritme, en de leden van die familie zijn het onderling oneens. Geef dezelfde bytes aan MODBUS, aan CCITT-FALSE en aan XMODEM, en je krijgt drie 16-bits getallen terug die niets met elkaar gemeen hebben.

Vijf constanten bepalen welk familielid je gebruikt: poly, init, refin, refout en xorout. Verander er één en de uitvoer verandert compleet. Er blijft geen restje gelijkenis over dat je nog zou kunnen waarschuwen. De meeste vragen van het type “waarom komt mijn CRC niet overeen met die van het apparaat” houden precies daar op: beide kanten gebruiken een andere variant, en niemand heeft opgeschreven welke.

Elke waarde in deze gids komt uit een geparametriseerd CRC-model dat draaide op Python 3.14.7 onder macOS, op vier manieren nagerekend: tegen zlib.crc32 en binascii.crc_hqx uit de standaardbibliotheek, tegen de gepubliceerde checkwaarden in de CRC-catalogus van RevEng, en tegen de documentatie van de fabrikant voor elke parameterset.

1. Hetzelfde frame, vier CRC-16-uitkomsten

Neem een echt Modbus RTU-verzoek. Slave 01, functiecode 03 (read holding registers), startadres 0x0000, aantal 0x000A:

01 03 00 00 00 0A

Dezelfde zes bytes door vier varianten:

VariantUitkomstOp de lijn (laagste byte eerst)
CRC-16/MODBUS0xCDC5C5 CD
CRC-16/IBM-3740 (CCITT-FALSE)0x042828 04
CRC-16/XMODEM0x0A3838 0A
CRC-16/ARC0xD6C5C5 D6

Niets verbindt die vier waarden. Ze delen geen nibblepatroon. Je haalt er ook geen vaste constante uit, en met omkeren of omwisselen kom je van de een nooit bij de ander. Twee ervan beginnen met dezelfde byte op de lijn, en dat is puur toeval.

De tekst “CRC-16” in een datasheet draagt dus bijna geen informatie. Je weet dat de uitvoer 16 bits breed is, en daar houdt het op. Wil je een uitkomst in een ander talstelsel bekijken terwijl je vergelijkt met een apparaat dat binary afdrukt, dan wisselt de omrekentool voor talstelsels een 16-bits waarde tussen hex en binary zonder dat je over padding hoeft na te denken.

2. Wat elk van de vijf parameters verandert

Onder elke variant zit dezelfde machine: een schuifregister dat één bit tegelijk opeet en er een constante in XORt zodra er een 1 aan de bovenkant uit valt. De parameters bepalen wat het register binnengaat en welke richting de bits op reizen, plus één laatste XOR op de weg naar buiten.

De hele motor past in veertien regels Python. Hij werkt bit voor bit, traag maar leesbaar, en hij reproduceert elke waarde in dit artikel:

def crc(data, width, poly, init, refin, refout, xorout):
    top = 1 << (width - 1)
    mask = (1 << width) - 1
    reg = init
    for byte in data:
        if refin:
            byte = int(f"{byte:08b}"[::-1], 2)
        reg ^= byte << (width - 8)
        for _ in range(8):
            reg = ((reg << 1) ^ poly) if reg & top else (reg << 1)
            reg &= mask
    if refout:
        reg = int(f"{reg:0{width}b}"[::-1], 2)
    return reg ^ xorout

De uitvoer van deze motor kun je naast de Python-standaardbibliotheek leggen. zlib.crc32 en binascii.crc_hqx geven elk een onafhankelijk antwoord, en alle drie komen overeen:

zlib.crc32(b"123456789")               = 0xCBF43926   engine above = 0xCBF43926   MATCH
binascii.crc_hqx(b"123456789", 0x0000) = 0x31C3       CRC-16/XMODEM = 0x31C3      MATCH
binascii.crc_hqx(b"123456789", 0xFFFF) = 0x29B1       CCITT-FALSE   = 0x29B1      MATCH

poly: twee kampen, 0x8005 en 0x1021

De polynoom is de constante die terug in het register wordt geXORd. Hij staat genoteerd in “normale” vorm, met de bovenste bit impliciet, dus 0x8005 betekent x^16 + x^15 + x^2 + 1 en 0x1021 betekent x^16 + x^12 + x^5 + 1. De lus van schuiven en XORen is een staartdeling van polynomen over GF(2). De polynoom speelt de deler. Het register houdt de lopende rest vast, en elke bit van het bericht brengt de deling één stap verder.

Bijna elke CRC-16 die je tegenkomt gebruikt een van die twee. 0x8005 dekt ARC, MODBUS en USB. 0x1021 dekt de hele CCITT-kluwen plus XMODEM, KERMIT en de RFID-varianten. De polynoom alleen wijst nooit één variant aan.

init: de startwaarde van het register

Twee waarden overheersen: 0x0000 en 0xFFFF. Het verschil telt zwaarder dan het lijkt. Begin je op nul, dan laat een nulbyte het register op nul staan, dus 00 00 01 en 01 leveren identieke CRC’s op. Een bericht dat onderweg voorloopnullen krijgt of verliest, komt zo gewoon door de controle. Beginnen op 0xFFFF haalt die blinde vlek weg, en daarom gebruiken Modbus, CCITT-FALSE en USB die waarde allemaal.

refin en refout: bitvolgorde, geen bytevolgorde

refin keert de acht bits van elke ingaande byte om voordat die het register binnengaat. refout keert het eindregister om vlak voor de laatste XOR. Hardware die data LSB-first naar buiten schuift, krijgt deze spiegelingen gratis, en daarom komen de gespiegelde varianten meestal uit seriële protocollen.

Dit is het parameterpaar dat het vaakst met endianness wordt verward. Het speelt op een ander niveau, en sectie 6 haalt de twee uit elkaar.

xorout: de laatste XOR

Dit is de laatste stap, toegepast op het register na refout. Voor CRC-16 is het meestal 0x0000 of 0xFFFF; de CRC-32-familie gebruikt 0xFFFFFFFF. Het is de goedkoopste parameter om fout te hebben, want een afwijking hier ziet er precies zo uit als een afwijking ergens anders.

width: 8, 16 of 32 bits

De breedte bepaalt het detectieplafond. Een CRC van breedte n vangt elke aaneengesloten foutreeks tot n bits lang, en mist een willekeurige verminking met een kans van ongeveer 2^-n. Dat is 1 op 65.536 voor CRC-16 en 1 op 4,3 miljard voor CRC-32.

Als je bij CRC-16/XMODEM begint en telkens precies één parameter verandert, tegen de standaard testinvoer 123456789:

baseline CRC-16/XMODEM                        = 0x31C3
init 0x0000 -> 0xFFFF   (becomes CCITT-FALSE) = 0x29B1
refin/refout -> true    (becomes KERMIT)      = 0x2189
xorout 0x0000 -> 0xFFFF                       = 0xCE3C
poly 0x1021 -> 0x8005                         = 0xFEE8

Eén omgezette vlag geeft een volstrekt andere uitvoer. CRC kent geen begrip “dichtbij”. Twee uitkomsten komen overeen, of ze zeggen je niets over hoe ver de invoer uit elkaar lag. Staren naar het verschil levert dus nooit een oorzaak op. De binnenste lus bestaat uit niets dan XOR en schuifbewerkingen; de complete gids over bitwise-operaties behandelt die operatoren zelf, en dit artikel gaat ervan uit dat je ze kent.

3. “CCITT” is een slechte naam

De CRC-catalogus van RevEng telt in september 2026 31 verschillende 16-bits CRC-definities, en drie daarvan dragen het label CCITT. Geen van die drie is het met de andere eens. De vier rijen hieronder delen een polynoom en een invoer, en komen uit op vier waarden zonder onderling verband:

Gangbare naamNaam in de cataloguscheckwaardeinitrefin/refoutxorout
CCITT-FALSECRC-16/IBM-37400x29B10xFFFFfalse0x0000
XMODEMCRC-16/XMODEM0x31C30x0000false0x0000
de “echte” CCITTCRC-16/KERMIT0x21890x0000true0x0000
CRC-16/MCRF4XX0x6F910xFFFFtrue0x0000

De geschiedenis is kort en helpt niet. De catalogus noemt CRC-16/KERMIT met de aliassen CRC-CCITT en CRC-16/CCITT-TRUE, en die variant is gespiegeld. Een ongespiegelde implementatie met init 0xFFFF circuleerde ook breed onder de naam CCITT, en daarom legt de catalogus “CCITT-FALSE” vast als alias van CRC-16/IBM-3740. XMODEM zit ertussenin: dezelfde polynoom, geen spiegeling, init nul.

Zegt een datasheet dus CCITT, dan heeft hij je verteld dat de polynoom 0x1021 is en verder niets. Je houdt vier kandidaten over, en de verkeerde kiezen levert een waarde op die er net zo geloofwaardig uitziet als de juiste.

Noteer parameters, geen namen. poly=0x1021, init=0xFFFF, refin=false, refout=false, xorout=0x0000 in je protocoldocument zetten kost één regel en maakt de vraag voorgoed dood. “CRC-16/CCITT” opschrijven regelt niets.

4. Zo bepaal je welke CRC-16-variant je hebt

De catalogus lost dit op met een vingerafdruk. Elke ingang publiceert een checkwaarde: de CRC van de negen ASCII-bytes 123456789. Haal die string door de implementatie die voor je ligt en zoek de uitkomst op.

Variantcheckwaardepolyinitrefinrefoutxorout
CRC-16/ARC (IBM/LHA)0xBB3D0x80050x0000truetrue0x0000
CRC-16/MODBUS0x4B370x80050xFFFFtruetrue0x0000
CRC-16/USB0xB4C80x80050xFFFFtruetrue0xFFFF
CRC-16/IBM-3740 (CCITT-FALSE)0x29B10x10210xFFFFfalsefalse0x0000
CRC-16/XMODEM0x31C30x10210x0000falsefalse0x0000
CRC-16/KERMIT (de echte CCITT)0x21890x10210x0000truetrue0x0000
CRC-16/GENIBUS0xD64E0x10210xFFFFfalsefalse0xFFFF
CRC-16/MCRF4XX0x6F910x10210xFFFFtruetrue0x0000
CRC-32/ISO-HDLC (zip, PNG, zlib)0xCBF439260x04C11DB70xFFFFFFFFtruetrue0xFFFFFFFF
CRC-32/BZIP20xFC8919180x04C11DB70xFFFFFFFFfalsefalse0xFFFFFFFF
CRC-32C (Castagnoli, iSCSI)0xE30692830x1EDC6F410xFFFFFFFFtruetrue0xFFFFFFFF
CRC-8/SMBUS0xF40x070x00falsefalse0x00
CRC-8/MAXIM-DOW (1-Wire)0xA10x310x00truetrue0x00

Eén detail laat verrassend veel van deze vergelijkingen stranden: 123456789 staat voor de negen bytes 31 32 33 34 35 36 37 38 39, niet voor het getal 123456789 en niet voor een string met afsluitende nulbyte. Geeft je taal de functie een wide string mee of plakt ze er een afsluitteken achter, dan reken je over andere bytes en mist elke rij. Payloads buiten ASCII zetten er een tweede valkuil bij: dezelfde tekst als UTF-8 en als Windows-1252 zijn twee verschillende bytereeksen, en dus twee verschillende CRC’s. De ASCII-tabel en converter laat de byte achter elk teken zien, en daarmee is die vraag beslecht.

Komt de checkwaarde met geen enkele rij overeen, sluit dan eerst de saaie oorzaken uit voordat je een eigen polynoom verdenkt:

  1. Je leest de uitkomst mogelijk omgekeerd van de lijn.
  2. De zender telt een adresbyte, een lengtebyte of het CRC-veld zelf wel of juist niet mee.
  3. De fabrikant hanteert een init die noch 0x0000 noch 0xFFFF is. Dat komt voor in propriëtaire meterprotocollen en staat meestal weggestopt in een voetnoot.

Alle combinaties aflopen

Wil de fabrikant het niet vertellen en kun je hun firmware niet lezen, vraag dan om één ding: een opgenomen frame plus de CRC die hun apparaat ervoor produceerde. Ga daarna alles langs. Twee polynomen, twee initwaarden, refin en refout onafhankelijk van elkaar en twee xorout-waarden komen uit op 32 combinaties, en dat is niets:

target = 0x4B37                    # de waarde die hun implementatie teruggaf
for poly in (0x8005, 0x1021):
    for init in (0x0000, 0xFFFF):
        for refin in (False, True):
            for refout in (False, True):
                for xorout in (0x0000, 0xFFFF):
                    if crc(b"123456789", 16, poly, init, refin, refout, xorout) == target:
                        print(f"poly=0x{poly:04X} init=0x{init:04X} "
                              f"refin={refin} refout={refout} xorout=0x{xorout:04X}")
poly=0x8005 init=0xFFFF refin=True refout=True xorout=0x0000

Eén treffer, en dat is CRC-16/MODBUS. Geef het een echt frame in plaats van 123456789 en dezelfde reeks van 32 combinaties werkt op elk bericht waarvan je een bekende goede CRC hebt. Overleven meerdere combinaties één monster, neem dan een tweede frame en houd de doorsnede over.

5. Modbus RTU in de praktijk

Modbus RTU gebruikt CRC-16/MODBUS: polynoom 0x8005, init 0xFFFF, gespiegeld in en uit, geen laatste XOR. Voor ons verzoek van zes bytes is de CRC 0xCDC5, en het complete frame wordt:

01 03 00 00 00 0A C5 CD

De volgorde op de lijn is omgekeerd aan hoe je de waarde schrijft

De waarde is 0xCDC5. De bytes die aan het frame worden geplakt zijn C5 CD. Modbus schrijft de laagste CRC-byte eerst voor, precies andersom dan de volgorde waarin je het hexgetal leest, en daar gaan mensen voortdurend de mist mee in. Elk ander veld van meerdere bytes in datzelfde frame, inclusief die registerteller 00 0A, is big-endian. De CRC is de uitzondering.

Dat heeft een handig neveneffect. Bereken CRC-16/MODBUS over het hele frame, CRC-bytes inbegrepen, en de uitkomst is:

0x0000

Dat is de complete validatieroutine van de ontvanger. Je knipt de laatste twee bytes er niet af en je vergelijkt ze nergens mee: draai de CRC over alles wat binnenkwam en controleer op nul. Minder stappen betekent minder plekken waar je de bytes verkeerd om kunt zetten.

Waarom Modbus-documentatie 0xA001 laat zien

Open zowat elke Modbus-implementatie en de constante in de broncode is 0xA001, niet 0x8005. Allebei kloppen. 0xA001 is 0x8005 met zijn 16 bits omgekeerd, en het hoort bij de gespiegelde vorm van het algoritme, waarin het register naar rechts schuift in plaats van naar links en de ingaande bytes geen omkering per byte nodig hebben. Beide implementaties geven identieke uitvoer; alleen de binnenkant verschilt. 0xA001 in de broncode is een betrouwbaar teken van een gespiegelde CRC-16-implementatie.

Let in een opname op nog één ding. Modbus ASCII is een aparte framing die elke byte als twee hextekens draagt tussen een 3A (:) vooraan en een 0D 0A achteraan, en die gebruikt een LRC in plaats van een CRC. Zie je in je trace 3A 30 31 30 33 waar je 01 03 verwachtte, dan zit je in ASCII-modus en zal geen enkele CRC-variant ooit kloppen. De ASCII-tabel zet die bytes direct terug om naar tekens.

Hetzelfde algoritme in C

Modbus-firmware gebruikt vrijwel nooit het Python-model hierboven, maar de gespiegelde vorm rechtstreeks: naar rechts schuiven en XORen met 0xA001:

uint16_t crc16_modbus(const uint8_t *buf, size_t len) {
    uint16_t crc = 0xFFFF;
    for (size_t i = 0; i < len; i++) {
        crc ^= buf[i];
        for (int b = 0; b < 8; b++)
            crc = (crc & 1) ? (crc >> 1) ^ 0xA001 : crc >> 1;
    }
    return crc;
}

Gevoed met het frame 01 03 00 00 00 0A geeft dit 0xCDC5 terug, dezelfde waarde die de Python-motor produceerde. De teststring 123456789 levert 0x4B37 op. Beide draaiden onder Apple clang 21 en komen bit voor bit overeen met de tabel in sectie 4.

6. refin/refout is geen endianness

Deze twee wonen op verschillende niveaus, en in een Modbus-frame komen ze allebei tegelijk voor. Daar ontstaat de verwarring.

Endianness gaat over bytes binnen een waarde van meerdere bytes: of 0xCDC5 wordt opgeslagen of verstuurd als CD C5 of als C5 CD. Binnen een byte beweegt er niets. Dat is het niveau dat big-endian versus little-endian volledig behandelt, en dit artikel herhaalt het niet.

Spiegeling gaat over bits binnen één byte. refin keert de acht bits van elke byte om voordat het register die ziet: bit 0 wordt bit 7. De byte houdt zijn plek in het bericht. Geen van beide instellingen heeft enig effect op de andere.

In een Modbus-frame gebeuren ze allebei, los van elkaar:

  • Binnen het algoritme staan refin en refout op true, dus worden bits binnen bytes omgekeerd.
  • Op de lijn wordt de afgeronde CRC met de laagste byte eerst aangeplakt, en dat is een keuze over bytevolgorde die het protocol maakt.

Zet je de spiegeling uit om een probleem met bytevolgorde te “repareren”, dan heb je opeens een volledig andere variant. Wissel je de laatste bytes van het frame om ter compensatie van een verkeerde spiegeling, dan krijg je een waarde die op een nieuwe manier fout is. Diagnosticeer één ding tegelijk: krijg eerst de checkwaarde goed met het algoritme alleen, en pak daarna de opbouw van het frame aan.

7. CRC-32 of CRC-16: welke moet je kiezen?

CRC-32 heeft hetzelfde probleem als CRC-16, alleen minder zichtbaar, omdat één variant zo volledig domineert dat de meeste ontwikkelaars nooit leren dat er andere bestaan.

Variantcheckwaardepolyrefin/refout
CRC-32/ISO-HDLC0xCBF439260x04C11DB7true
CRC-32/BZIP20xFC8919180x04C11DB7false
CRC-32C (Castagnoli)0xE30692830x1EDC6F41true

ISO-HDLC is wat zlib.crc32 berekent, en die zit overal aan de webkant van de stack. Zip bewaart hem per ingang in de central directory, en elke PNG-chunk eindigt met een exemplaar dat het chunktype en de data dekt. De frame check sequence van ethernet gebruikt dezelfde parameterset aan het eind van elk frame dat je server verstuurt. BZIP2 is diezelfde polynoom met de spiegelingen uit, en die levert een waarde op die niets deelt met ISO-HDLC.

CRC-16 duikt ook in die buurt op: Redis Cluster stuurt een key naar een van zijn 16.384 slots met CRC16(key) mod 16384, en daarom belanden keys met dezelfde hash tag op dezelfde node.

Waarom CRC-32C de hardwareloterij won

CRC-32C gebruikt een andere polynoom met betere foutdetectie over de korte blokken die opslag- en netwerkprotocollen versturen. Dat leverde hem iSCSI, de metadata-checksums van ext4, SCTP en Btrfs op. Daarna zette Intel hem in silicium: de SSE4.2-instructie crc32 berekent CRC-32C rechtstreeks, waardoor het op moderne x86 een vrijwel gratis integriteitscontrole wordt. Kies je vandaag een CRC voor nieuwe code en heb je geen compatibiliteitseis, dan is dit de juiste.

Geen van deze is een hash om een download mee te verifiëren. Wil je een checksum die bevestigt dat een bestand intact is aangekomen, dan is de MD5-hashgenerator het gebruikelijke gereedschap, en MD5 vs SHA-256 behandelt welke hash je waarvoor kunt vertrouwen. Een CRC beantwoordt “is dit beschadigd geraakt”; een cryptografische hash beantwoordt “is dit precies de inhoud die ik verwacht”.

8. Een CRC houdt manipulatie niet tegen

Hier zijn twee JSON-berichten met tegengestelde betekenis en dezelfde CRC-32:

message A = b'{"to":"alice","amount":100}  H\xf6\xc0E'
message B = b'{"to":"mallory","amount":999}\xb2\xb2\xc2\xc2'
CRC-32(A) = 0x12345678
CRC-32(B) = 0x12345678

SHA-256 over diezelfde twee:

A -> a83b90f5e3f21dd32039e0e693a8b15864eda83e258c115deeee50a60c09ae23
B -> f9319ee0507d719c7260535dff33df721ddd9c0e1857690f3d8e02f92601b742

Hier is niets met brute kracht gezocht. De laatste bytes zijn algebraïsch opgelost. CRC is een lineaire functie, en vier bytes achter een bericht plakken beeldt af op de CRC-32-uitvoer als een bijectie. Voor elk bericht en elke doelwaarde bestaat er dus precies één achtervoegsel van vier bytes dat je daar brengt, en dat achtervoegsel reken je uit.

De vier opgeloste bytes 46 C9 6E 0B achter hello world plakken:

CRC-32(b'hello world' + 46 C9 6E 0B) = 0xDEADBEEF   target 0xDEADBEEF   MATCH

Een aanvaller die je payload kan aanpassen, kan dus ook je CRC bijwerken, in constante tijd, zonder ergens naar te hoeven zoeken. Het bericht vooraf laten gaan door een geheim redt het niet: bij een bewerking die de lengte gelijk houdt, hangt de correctie op de CRC alleen af van de bits die veranderden, waardoor je die kunt berekenen zonder het geheim ooit te kennen. Dat is de vorm van de aanval die WEP brak.

CRC beschermt tegen ruis op de verbinding, die willekeurig is en geen doel heeft. Een tegenstander is geen van beide, en daartegen geeft een CRC je niets. Is de eis authenticiteit in plaats van integriteit, dan heb je een constructie met een sleutel nodig: de HMAC-generator maakt er een over elke payload en sleutel, en waarom verificatie van webhook-signatures mislukt loopt de onderdelen langs waar mensen over struikelen als ze het op een echt endpoint aansluiten.

9. FAQ

Is CRC-16/CCITT hetzelfde als CRC-16/CCITT-FALSE?

Nee, CRC-16/CCITT-FALSE en CRC-16/CCITT zijn verschillende varianten. CCITT-FALSE is CRC-16/IBM-3740: init 0xFFFF, geen spiegeling, checkwaarde 0x29B1. De variant die men met kaal CCITT meestal bedoelt is CRC-16/KERMIT: init 0x0000, gespiegeld, check 0x2189. Ze delen de polynoom 0x1021 en zijn het verder nergens over eens.

Waarom geeft een online calculator iets anders dan mijn apparaat?

Andere parameters, bijna altijd. De tool valt terug op de ene variant en het apparaat implementeert de andere. Haal de ASCII-bytes 123456789 door allebei, vergelijk de twee checkwaarden met de tabel in sectie 4, en meestal wijst de afwijkende parameter zichzelf aan.

Waarom zet Modbus de laagste CRC-byte eerst?

Omdat de specificatie het zo voorschrijft, en het is het enige veld in het frame dat zich zo gedraagt. Registeradressen en tellers zijn big-endian; de CRC aan het eind niet. Bereken CRC-16/MODBUS over het hele frame inclusief die twee bytes en controleer op 0x0000 in plaats van ze zelf om te draaien.

Wat keren refin en refout precies om?

Bits binnen een byte, nooit bytes binnen een bericht. refin keert de acht bits van elke ingaande byte om vóór de verwerking; refout keert het eindregister om vlak voor de laatste XOR. Beide staan los van endianness, dat bepaalt hoe een waarde van meerdere bytes op de lijn wordt neergelegd.

Moet ik CRC-16 of CRC-32 gebruiken?

CRC-16 mist een willekeurige verminking ongeveer één keer op 65.536, CRC-32 één keer op 4,3 miljard. Voor korte seriële frames van een paar tientallen bytes voldoet CRC-16 prima, en meestal schrijft het protocol hem toch al voor. Voor bestanden, netwerkframes en alles boven een paar kilobytes gebruik je CRC-32.

Kan ik een CRC als API-signature gebruiken?

Nee, een CRC kan niet dienen als API-signature. CRC is lineair, dus iedereen die de payload aanpast kan een passende waarde opnieuw berekenen, en vier gekozen bytes erachter plakken bereikt elke CRC-32-doelwaarde die je noemt. Signatures hebben een geheime sleutel en een niet-lineaire constructie nodig. Gebruik HMAC met SHA-256.

Kun je de oorspronkelijke data uit een CRC-waarde terughalen?

Nee, de oorspronkelijke data valt niet uit een CRC-waarde terug te halen. Een CRC-16 perst elke invoer samen tot 16 bits, dus oneindig veel berichten delen elke waarde. De omgekeerde richting is voor aanvallers wel bruikbaar: bij een gegeven doelwaarde kun je een bericht construeren dat die waarde oplevert, en precies daarom authenticeert een CRC niets.

In het document van de fabrikant staat alleen “CRC-16”. Hoe achterhaal ik de parameters?

Vraag om één opgenomen frame plus de CRC die hun apparaat ervoor berekende, en laat daar de 32 combinaties uit sectie 4 op los. Overleeft er meer dan één parameterset, herhaal het dan met een tweede frame en houd de doorsnede over. Twee monsters zijn vrijwel altijd beslissend.

Tags: crc checksum modbus embedded data-integrity

Gerelateerde artikelen

Alle artikelen bekijken