Variantes CRC-16 : pourquoi MODBUS, CCITT et XMODEM diffèrent
Sous le nom CRC-16 se cache une famille entière d’algorithmes, dont les membres ne sont d’accord sur rien. Donnez les mêmes octets à MODBUS, puis à CCITT-FALSE, puis à XMODEM : vous récupérez trois nombres de 16 bits sans aucun rapport entre eux.
Cinq constantes déterminent lequel de ces membres tourne chez vous : poly, init, refin, refout et xorout. Changez-en une seule et la sortie change du tout au tout, sans la moindre ressemblance partielle pour vous mettre la puce à l’oreille. C’est toute la réponse à « pourquoi mon CRC ne correspond-il pas à celui de l’appareil ? » : vous et l’appareil exécutez deux variantes différentes, et personne n’a écrit laquelle.
Restent quatre questions concrètes : ce que fait chaque paramètre, comment identifier la variante que vous avez réellement entre les mains, dans quel ordre Modbus RTU pose ses octets sur le fil, et pourquoi un CRC arrête le bruit de ligne sans gêner un attaquant.
Toutes les valeurs de ce guide proviennent d’un modèle CRC paramétrable exécuté sous Python 3.14.7 sur macOS, recoupées de quatre façons : avec
zlib.crc32etbinascii.crc_hqxde la bibliothèque standard, avec les valeurs de contrôle publiées dans le catalogue CRC RevEng, et avec la documentation constructeur de chaque jeu de paramètres.
1. Même trame, quatre résultats CRC-16
Voici une vraie requête Modbus RTU. Esclave 01, code fonction 03 (lecture de registres de maintien), adresse de départ 0x0000, quantité 0x000A :
01 03 00 00 00 0A
Six octets, et quatre réponses selon la variante :
| Variante | Résultat | Sur le fil (octet de poids faible en premier) |
|---|---|---|
| CRC-16/MODBUS | 0xCDC5 | C5 CD |
| CRC-16/IBM-3740 (CCITT-FALSE) | 0x0428 | 28 04 |
| CRC-16/XMODEM | 0x0A38 | 38 0A |
| CRC-16/ARC | 0xD6C5 | C5 D6 |
Rien ne relie ces quatre valeurs. Elles ne partagent aucun motif de quartets et aucune astuce de réordonnancement ne transforme l’une en l’autre ; l’écart qui les sépare n’est pas non plus une constante. Deux commencent par le même octet sur le fil, par pure coïncidence.
Conséquence pratique : la mention « CRC-16 » dans une fiche technique n’apporte presque aucune information. Elle vous dit que la sortie fait 16 bits de large, et s’arrête là. Si vous devez examiner un résultat dans une autre base pour le comparer à un appareil qui affiche du binaire, le convertisseur de base numérique fait passer une valeur de 16 bits de l’hexadécimal au binaire sans vous obliger à réfléchir au remplissage.
2. Cinq paramètres décident de tout
Sous chaque variante se cache la même machine : un registre à décalage qui avale un bit à la fois et applique un XOR avec une constante chaque fois qu’un 1 tombe par le haut. Les paramètres décident de ce qui entre dans le registre et du sens dans lequel les bits y circulent, puis de ce qu’on fait du résultat.
Voici le moteur complet en quatorze lignes de Python. C’est une implémentation bit à bit, lente mais lisible, et elle reproduit toutes les valeurs de cet article :
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
La sortie du moteur se recoupe avec la bibliothèque standard de Python. zlib.crc32 et binascii.crc_hqx donnent chacun une réponse indépendante, et les trois concordent :
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 : deux camps, 0x8005 et 0x1021
Le polynôme est la constante réinjectée dans le registre par XOR. Il s’écrit sous forme « normale », bit de poids fort implicite : 0x8005 signifie donc x^16 + x^15 + x^2 + 1 et 0x1021 signifie x^16 + x^12 + x^5 + 1. La boucle de décalage et de XOR est une division polynomiale posée sur GF(2). Chaque bit du message est une étape de la division, le polynôme est le diviseur, et le registre contient le reste courant.
Presque tous les CRC-16 que vous croiserez utilisent l’un de ces deux-là. 0x8005 couvre ARC, MODBUS et USB. 0x1021 couvre tout l’écheveau CCITT, plus XMODEM, KERMIT et les variantes RFID. Le polynôme seul n’identifie donc jamais une variante.
init : la valeur de départ du registre
Deux valeurs dominent : 0x0000 et 0xFFFF. L’écart compte davantage qu’il n’y paraît. Partez de zéro et un octet nul laisse le registre à zéro : 00 00 01 et 01 produisent alors des CRC identiques. Un message qui gagne ou perd des zéros de tête pendant le transit passe le contrôle. Démarrer à 0xFFFF supprime cet angle mort, et c’est pourquoi Modbus, CCITT-FALSE et USB l’emploient tous.
refin et refout : ordre des bits, pas des octets
refin inverse les huit bits de chaque octet d’entrée avant son passage dans le registre. refout inverse le registre final avant le dernier XOR. Le matériel qui sort les données bit de poids faible en tête obtient ces réflexions gratuitement, si bien que les variantes réfléchies sont en général celles nées dans les protocoles série.
C’est la paire de paramètres que l’on confond le plus souvent avec l’endianness (le boutisme). Il s’agit d’autre chose, à un autre niveau : la section 6 démêle les deux.
xorout : le XOR final
Dernière étape, appliquée au registre après refout. Généralement 0x0000 ou 0xFFFF pour le CRC-16, et 0xFFFFFFFF dans toute la famille CRC-32. C’est le paramètre qu’il est le plus facile de rater, parce qu’une erreur à cet endroit ressemble exactement à une erreur commise n’importe où ailleurs.
width : 8, 16 ou 32 bits
La largeur fixe le plafond de détection. Un CRC de largeur n attrape toute rafale d’erreurs jusqu’à n bits de long, et laisse passer une corruption aléatoire avec une probabilité d’environ 2^-n. Soit 1 sur 65 536 pour le CRC-16 et 1 sur 4,3 milliards pour le CRC-32.
En partant de CRC-16/XMODEM, on modifie exactement un paramètre à la fois, sur l’entrée de test standard 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
Un drapeau retourné, une sortie entièrement différente. Le CRC n’a aucune notion de « proche ». Deux résultats se correspondent, ou bien ils ne disent rien de l’écart entre les entrées : c’est pourquoi fixer un désaccord du regard ne localise jamais la cause. La boucle interne n’est faite que de XOR et de décalages ; le guide complet des opérations bit à bit traite ces opérateurs eux-mêmes, que cet article suppose acquis.
3. « CCITT » est un mauvais nom
Le catalogue CRC de RevEng recense, à la date de septembre 2026, 31 définitions distinctes de CRC 16 bits, et trois d’entre elles portent l’étiquette CCITT. Ces trois-là ne s’accordent avec aucune des autres. Même polynôme, même entrée, quatre résultats sans aucun rapport :
| Nom courant | Nom au catalogue | check | init | refin/refout | xorout |
|---|---|---|---|---|---|
| CCITT-FALSE | CRC-16/IBM-3740 | 0x29B1 | 0xFFFF | false | 0x0000 |
| XMODEM | CRC-16/XMODEM | 0x31C3 | 0x0000 | false | 0x0000 |
| le « vrai » CCITT | CRC-16/KERMIT | 0x2189 | 0x0000 | true | 0x0000 |
| — | CRC-16/MCRF4XX | 0x6F91 | 0xFFFF | true | 0x0000 |
L’historique est court et n’aide guère. Le catalogue référence CRC-16/KERMIT sous les alias CRC-CCITT et CRC-16/CCITT-TRUE, et celui-là est réfléchi. Une implémentation non réfléchie avec init 0xFFFF a elle aussi largement circulé sous le nom CCITT, d’où l’enregistrement de « CCITT-FALSE » comme alias de CRC-16/IBM-3740 dans le catalogue. XMODEM se place entre les deux : même polynôme, pas de réflexion, init à zéro.
Donc quand une fiche technique annonce CCITT, elle vous a dit que le polynôme est 0x1021, et rien de plus. Il vous reste quatre candidats, et un mauvais choix produit une valeur exactement aussi plausible que la bonne.
L’habitude à prendre : citez les paramètres plutôt que le nom de la variante. Écrire poly=0x1021, init=0xFFFF, refin=false, refout=false, xorout=0x0000 dans votre document de protocole prend une ligne et lève l’ambiguïté définitivement. Écrire « CRC-16/CCITT » ne fait rien de tel.
4. Comment identifier la variante CRC-16 que vous avez sous la main
Le catalogue règle la question par une empreinte. Chaque entrée publie une valeur de contrôle (check value) : le CRC des neuf octets ASCII 123456789. Faites passer cette chaîne dans l’implémentation que vous avez sous les yeux, puis cherchez le résultat dans le tableau.
| Variante | check | poly | init | refin | refout | xorout |
|---|---|---|---|---|---|---|
| CRC-16/ARC (IBM/LHA) | 0xBB3D | 0x8005 | 0x0000 | true | true | 0x0000 |
| CRC-16/MODBUS | 0x4B37 | 0x8005 | 0xFFFF | true | true | 0x0000 |
| CRC-16/USB | 0xB4C8 | 0x8005 | 0xFFFF | true | true | 0xFFFF |
| CRC-16/IBM-3740 (CCITT-FALSE) | 0x29B1 | 0x1021 | 0xFFFF | false | false | 0x0000 |
| CRC-16/XMODEM | 0x31C3 | 0x1021 | 0x0000 | false | false | 0x0000 |
| CRC-16/KERMIT (le vrai CCITT) | 0x2189 | 0x1021 | 0x0000 | true | true | 0x0000 |
| CRC-16/GENIBUS | 0xD64E | 0x1021 | 0xFFFF | false | false | 0xFFFF |
| CRC-16/MCRF4XX | 0x6F91 | 0x1021 | 0xFFFF | true | true | 0x0000 |
| CRC-32/ISO-HDLC (zip, PNG, zlib) | 0xCBF43926 | 0x04C11DB7 | 0xFFFFFFFF | true | true | 0xFFFFFFFF |
| CRC-32/BZIP2 | 0xFC891918 | 0x04C11DB7 | 0xFFFFFFFF | false | false | 0xFFFFFFFF |
| CRC-32C (Castagnoli, iSCSI) | 0xE3069283 | 0x1EDC6F41 | 0xFFFFFFFF | true | true | 0xFFFFFFFF |
| CRC-8/SMBUS | 0xF4 | 0x07 | 0x00 | false | false | 0x00 |
| CRC-8/MAXIM-DOW (1-Wire) | 0xA1 | 0x31 | 0x00 | true | true | 0x00 |
Un détail fait échouer beaucoup de ces comparaisons : 123456789 désigne les neuf octets 31 32 33 34 35 36 37 38 39, pas le nombre 123456789 ni une chaîne terminée par un octet nul. Si votre langage passe à la fonction une chaîne large ou ajoute un terminateur, vous calculez le CRC d’une autre entrée et aucune ligne ne correspondra. Les charges utiles non ASCII ajoutent un second piège : le même texte encodé en UTF-8 et en Windows-1252 donne deux séquences d’octets différentes, donc deux CRC différents. La table ASCII et son convertisseur donne l’octet de chaque caractère, ce qui permet d’écarter la question en quelques secondes.
Si la valeur de contrôle ne correspond à aucune ligne, écartez d’abord les causes banales avant de soupçonner un polynôme maison :
- Ordre des octets : vous lisez peut-être le résultat à l’envers sur le fil.
- Champs couverts : l’émetteur inclut ou exclut un octet d’adresse, un octet de longueur, ou le champ CRC lui-même.
- Un
initpropre au fabricant, qui n’est ni0x0000ni0xFFFF; cela existe dans les protocoles de compteurs propriétaires et se cache généralement dans une note de bas de page.
Retrouver les paramètres par force brute
Quand le constructeur refuse de vous répondre et que vous ne pouvez pas lire son firmware, demandez-lui une seule chose : une trame capturée accompagnée du CRC que son appareil a produit pour elle. Puis énumérez. Deux polynômes, deux valeurs d’init, refin et refout indépendants, deux valeurs de xorout : cela fait 32 combinaisons, autant dire rien.
target = 0x4B37 # la valeur renvoyée par leur implémentation
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
Une seule correspondance, et c’est CRC-16/MODBUS. Donnez-lui une vraie trame au lieu de 123456789 et le même balayage à 32 combinaisons fonctionne sur n’importe quel message dont vous connaissez le CRC correct. Si plusieurs combinaisons survivent à un échantillon, lancez une deuxième trame et gardez l’intersection des résultats.
5. Modbus RTU en pratique
Modbus RTU utilise CRC-16/MODBUS : polynôme 0x8005, init 0xFFFF, réflexion en entrée et en sortie, pas de XOR final. Pour notre requête de six octets, le CRC vaut 0xCDC5, et la trame complète est :
01 03 00 00 00 0A C5 CD
L’ordre sur le fil est l’inverse de l’écriture de la valeur
La valeur est 0xCDC5. Les octets ajoutés à la trame sont C5 CD. Modbus impose l’octet de poids faible du CRC en premier, soit l’inverse de l’ordre dans lequel vous lisez le nombre hexadécimal ; c’est l’inversion qu’on oublie le plus souvent en relisant sa propre trame. Tous les autres champs multi-octets de la même trame, y compris ce compte de registres 00 0A, sont en gros-boutiste. Le CRC est l’exception.
Il en découle une conséquence utile. Calculez le CRC-16/MODBUS sur la trame complète, octets de CRC inclus, et le résultat est :
0x0000
Voilà toute la routine de validation du récepteur. Inutile de détacher les deux octets de fin, de les permuter, puis de les comparer à une valeur calculée localement. Passez le CRC sur tout ce qui est arrivé et vérifiez que le résultat est nul : il ne reste plus un seul endroit où se tromper de sens.
Pourquoi la documentation Modbus affiche 0xA001
Ouvrez à peu près n’importe quelle implémentation Modbus : la constante dans le source est 0xA001, pas 0x8005. Les deux sont correctes. 0xA001 est 0x8005 dont les 16 bits ont été inversés, et il appartient à la forme réfléchie de l’algorithme, où le registre décale vers la droite au lieu de la gauche et où les octets d’entrée n’ont plus besoin d’être inversés un par un. Les deux implémentations produisent une sortie identique ; seuls les rouages diffèrent. Voir 0xA001 dans du code vous dit que l’implémentation est réfléchie ; le polynôme, lui, reste 0x8005.
Une parenthèse pour qui lit une capture. Modbus ASCII est un encadrement distinct, qui transporte chaque octet sous forme de deux caractères hexadécimaux entre un 3A (:) initial et un 0D 0A final, et qui emploie un LRC plutôt qu’un CRC. Si votre trace montre 3A 30 31 30 33 là où vous attendiez 01 03, vous êtes en mode ASCII et aucune variante de CRC ne correspondra jamais. La table ASCII retraduit directement ces octets en caractères.
Le même algorithme en C
Le firmware Modbus n’utilise presque jamais le modèle Python ci-dessus. Il emploie directement la forme réfléchie : décalage à droite, puis XOR avec 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;
}
Avec la trame 01 03 00 00 00 0A, cette fonction renvoie 0xCDC5, la même valeur que le moteur Python. La chaîne de contrôle 123456789 donne 0x4B37. Les deux ont été exécutés sous Apple clang 21 et correspondent bit pour bit aux tableaux des sections 1 et 4.
6. refin/refout n’est pas l’endianness
L’endianness porte sur les octets à l’intérieur d’une valeur multi-octets : savoir si 0xCDC5 est stocké ou transmis sous la forme CD C5 ou C5 CD. Rien ne bouge à l’intérieur d’un octet. C’est le niveau que gros-boutiste contre petit-boutiste traite en entier, et qu’il n’y a pas lieu de reprendre ici.
La réflexion porte sur les bits à l’intérieur d’un même octet. refin inverse les huit bits de chaque octet avant que le registre ne le voie : le bit 0 devient le bit 7. La position de l’octet dans le message ne change jamais. L’endianness ne peut pas voir cela, et la réflexion ne peut pas voir l’endianness.
Dans une trame Modbus, les deux se produisent, indépendamment l’une de l’autre :
- Dans l’algorithme,
refinetrefoutvalent true, donc les bits sont inversés à l’intérieur des octets. - Sur le fil, le protocole place le CRC terminé octet de poids faible en premier : une décision d’ordre des octets, cette fois.
Désactiver la réflexion pour « corriger » un problème d’ordre des octets produit une tout autre variante, et permuter les octets de fin de trame pour compenser une erreur de réflexion produit une valeur fausse d’une nouvelle manière. Diagnostiquez un point à la fois : obtenez d’abord la bonne valeur de contrôle avec l’algorithme seul, puis occupez-vous de la disposition de la trame.
7. CRC-32 ou CRC-16 : lequel choisir ?
Le CRC-32 souffre du même problème que le CRC-16, en moins visible, parce qu’une variante domine si complètement que la plupart des développeurs n’apprennent jamais qu’il en existe d’autres.
| Variante | check | poly | refin/refout |
|---|---|---|---|
| CRC-32/ISO-HDLC | 0xCBF43926 | 0x04C11DB7 | true |
| CRC-32/BZIP2 | 0xFC891918 | 0x04C11DB7 | false |
| CRC-32C (Castagnoli) | 0xE3069283 | 0x1EDC6F41 | true |
ISO-HDLC est ce que calcule zlib.crc32, et on le trouve partout du côté web de la pile. Zip le stocke pour chaque entrée dans le répertoire central. Chaque bloc PNG se termine par un CRC couvrant le type du bloc et ses données. La séquence de contrôle de trame d’Ethernet utilise le même jeu de paramètres à la fin de chaque trame que votre serveur envoie. BZIP2, c’est le même polynôme avec les réflexions désactivées, ce qui produit une valeur qui ne partage rien avec ISO-HDLC.
Le CRC-16 se montre aussi dans le voisinage : Redis Cluster route une clé vers l’un de ses 16 384 slots avec CRC16(key) mod 16384, ce qui explique que des clés portant le même hash tag atterrissent sur le même nœud.
Pourquoi CRC-32C a gagné la loterie matérielle
CRC-32C utilise un polynôme différent, qui détecte mieux les erreurs sur les blocs courts que les protocoles de stockage et de réseau envoient réellement. Cela lui a valu iSCSI, les sommes de contrôle des métadonnées ext4, SCTP et Btrfs. Puis Intel l’a gravé dans le silicium : l’instruction crc32 de SSE4.2 calcule directement CRC-32C, ce qui en fait un contrôle d’intégrité pratiquement gratuit sur les x86 modernes. Si vous choisissez aujourd’hui un CRC pour du code neuf et que rien ne vous contraint côté compatibilité, c’est celui-là qu’il faut prendre.
Aucun d’eux n’est une fonction de hachage destinée à vérifier un téléchargement. Quand vous voulez une somme de contrôle confirmant qu’un fichier est arrivé intact, le générateur de hash MD5 est l’outil familier, et MD5 contre SHA-256 explique à quelle empreinte se fier, et pour quoi. Un CRC répond à « est-ce que ceci a été corrompu ? » ; un hachage cryptographique répond à « est-ce exactement le contenu que j’attends ? ».
8. Un CRC n’arrête pas la falsification
Voici deux messages JSON de sens opposés et de même 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 sur ces deux mêmes messages :
A -> a83b90f5e3f21dd32039e0e693a8b15864eda83e258c115deeee50a60c09ae23
B -> f9319ee0507d719c7260535dff33df721ddd9c0e1857690f3d8e02f92601b742
Une collision n’a rien d’étonnant sur 32 bits ; la façon de l’obtenir, si. Personne n’a rien cassé par force brute : les quatre octets de fin se résolvent algébriquement. Le CRC est une fonction linéaire, et ajouter quatre octets à un message se projette sur la sortie CRC-32 comme une bijection ; pour n’importe quel message et n’importe quelle valeur cible, il existe donc exactement un suffixe de quatre octets qui vous y mène, et le trouver relève de l’arithmétique.
La démonstration, en ajoutant les quatre octets calculés 46 C9 6E 0B à hello world :
CRC-32(b'hello world' + 46 C9 6E 0B) = 0xDEADBEEF target 0xDEADBEEF MATCH
Un attaquant capable de modifier votre charge utile peut donc aussi rectifier votre CRC, en temps constant, sans rien avoir à chercher. Préfixer le message par un secret ne le sauve pas : pour une modification qui préserve la longueur, la correction à appliquer au CRC ne dépend que des bits qui ont changé, et se calcule donc sans jamais connaître le secret. C’est la forme de l’attaque qui a cassé WEP.
Le CRC défend contre le bruit de transmission, qui est aléatoire et sans objectif. Un adversaire, lui, choisit ses bits. Quand le besoin est l’authenticité plutôt que l’intégrité, il vous faut une construction à clé : le générateur HMAC en produit une sur n’importe quelle charge utile et n’importe quelle clé, et pourquoi la vérification de signature de webhook échoue passe en revue les points qui font trébucher au moment de la brancher sur un vrai endpoint.
9. FAQ
CRC-16/CCITT est-il la même chose que CRC-16/CCITT-FALSE ?
Non, CRC-16/CCITT-FALSE et CRC-16/CCITT sont deux variantes différentes. CCITT-FALSE, c’est CRC-16/IBM-3740 : init 0xFFFF, non réfléchi, valeur de contrôle 0x29B1. La variante que l’on désigne d’ordinaire par un simple « CCITT » est CRC-16/KERMIT : init 0x0000, réfléchi, check 0x2189. Elles partagent le polynôme 0x1021 et ne s’accordent sur rien d’autre.
Pourquoi un calculateur en ligne donne-t-il un autre résultat que mon appareil ?
Des paramètres différents, presque toujours. L’outil part d’une variante par défaut et l’appareil en implémente une autre. Faites passer les octets ASCII 123456789 dans les deux, comparez les deux valeurs de contrôle au tableau de la section 4, et le paramètre fautif se désigne en général tout seul.
Pourquoi Modbus place-t-il l’octet de poids faible du CRC en premier ?
Parce que la spécification le dit, et c’est le seul champ de la trame à se comporter ainsi. Les adresses et les compteurs de registres sont en gros-boutiste ; le CRC final, non. Calculez le CRC-16/MODBUS sur la trame entière, ces deux octets compris, et vérifiez que vous obtenez 0x0000, plutôt que de les réordonner vous-même.
Qu’inversent exactement refin et refout ?
Des bits à l’intérieur d’un octet, jamais des octets à l’intérieur d’un message. refin inverse les huit bits de chaque octet d’entrée avant traitement ; refout inverse le registre final avant le dernier XOR. Les deux sont indépendants de l’endianness, qui régit la disposition d’une valeur multi-octets sur le fil.
Faut-il utiliser CRC-16 ou CRC-32 ?
Le CRC-16 laisse passer une corruption aléatoire environ une fois sur 65 536, le CRC-32 une fois sur 4,3 milliards. Pour de courtes trames série de quelques dizaines d’octets, le CRC-16 convient très bien, et le protocole l’impose de toute façon la plupart du temps. Pour des fichiers, des trames réseau et tout ce qui dépasse quelques kilo-octets, utilisez le CRC-32.
Puis-je utiliser un CRC comme signature d’API ?
Non, un CRC ne peut pas servir de signature d’API. Le CRC est linéaire : quiconque altère la charge utile peut recalculer une valeur qui correspond, et ajouter quatre octets bien choisis permet d’atteindre n’importe quelle cible CRC-32 que vous nommerez. Une signature exige une clé secrète et une construction non linéaire. Utilisez HMAC avec SHA-256.
Peut-on retrouver les données d’origine à partir d’une valeur de CRC ?
Non, les données d’origine ne peuvent pas être reconstituées à partir d’une valeur CRC. Un CRC-16 comprime n’importe quelle entrée en 16 bits : une infinité de messages partagent donc chaque valeur. Le sens inverse reste pourtant utile aux attaquants : à partir d’une valeur cible, vous pouvez construire un message qui la produit, et c’est exactement pour cela qu’un CRC n’authentifie rien.
Le document du constructeur dit seulement « CRC-16 ». Comment cerner les paramètres ?
Demandez une trame capturée accompagnée du CRC que leur appareil a calculé pour elle, puis lancez le balayage à 32 combinaisons de la section 4 sur ce couple. Si plus d’un jeu de paramètres survit, recommencez avec une deuxième trame et conservez l’intersection. Deux échantillons sont presque toujours décisifs.