Aynı baytlar neden dört farklı CRC-16 sonucu veriyor
CRC-16 tek bir algoritmanın değil, bir ailenin adı; üyeleri de birbiriyle anlaşamıyor. Aynı baytları MODBUS’a, CCITT-FALSE’a ve XMODEM’e verin; geriye ortak hiçbir yanı olmayan üç tane 16 bitlik sayı gelir.
Hangi üyeyi çalıştırdığınızı beş sabit belirler: poly, init, refin, refout ve xorout. Birini değiştirin, çıktı baştan aşağı başkalaşır; sizi uyaracak kısmi bir benzerlik bile kalmaz. “CRC’m neden cihazınkiyle tutmuyor” sorularının çoğu tam burada biter: iki taraf farklı çeşitler çalıştırıyordur ve hangisini kullandıklarını kimse yazmamıştır.
Bu rehberdeki her değer, macOS üzerinde Python 3.14.7 ile çalıştırılan parametreli bir CRC modelinden çıktı. Dört ayrı yoldan doğruladık: standart kütüphanenin
zlib.crc32vebinascii.crc_hqxfonksiyonlarıyla, RevEng CRC kataloğunda yayımlanan check değerleriyle, bir de her parametre kümesi için üretici firma dokümantasyonuyla.
1. Aynı çerçeve, dört CRC-16 sonucu
Aşağıda gerçek bir Modbus RTU isteği var. Slave 01, fonksiyon kodu 03 (holding register okuma), başlangıç adresi 0x0000, adet 0x000A:
01 03 00 00 00 0A
Aynı altı bayt, dört çeşitten geçtiğinde:
| Çeşit | Sonuç | Hatta (önce düşük bayt) |
|---|---|---|
| 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 |
Bu dört değeri birbirine bağlayan hiçbir şey yok. Ortak bir nibble deseni taşımıyorlar, aralarındaki fark da sabit değil; sıralamayla oynayarak birini diğerine çeviremezsiniz. İkisinin hatta aynı baytla başlaması rastlantı.
Yani bir datasheet’te geçen “CRC-16” ifadesi neredeyse hiçbir bilgi taşımıyor. Size çıktının 16 bit genişliğinde olduğunu söyler ve orada durur. Bir sonuca başka bir tabanda bakmanız, örneğin ikilik yazdıran bir cihazla karşılaştırma yapmanız gerekirse, sayı tabanı dönüştürücü 16 bitlik bir değeri dolgu derdine düşmeden onaltılık ile ikilik arasında çevirir.
2. Beş parametrenin her biri neyi değiştirir
Her çeşidin altında aynı makine yatıyor: bir seferde tek bir bit yutan bir kaydırma yazmacı ve tepeden bir 1 düştüğü anda içeri XOR’lanan bir sabit. Parametreler, yazmaca neyin girdiğine ve bitlerin hangi yöne yürüdüğüne karar veriyor; bir de çıkışta uygulanan son bir XOR var.
Bütün motor on dört satır Python. Bit bit ilerleyen bir uygulama; yavaş ama okunaklı ve bu yazıdaki her değeri yeniden üretiyor:
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
Motorun çıktısını Python standart kütüphanesine karşı sınayabilirsiniz. zlib.crc32 ve binascii.crc_hqx birbirinden bağımsız birer yanıt veriyor ve üçü de tutuyor:
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: iki kamp, 0x8005 ve 0x1021
Polinom, yazmacın içine geri XOR’lanan sabittir. En üst biti örtük bırakılarak, yani “normal” biçimde yazılır: 0x8005 demek x^16 + x^15 + x^2 + 1, 0x1021 demek x^16 + x^12 + x^5 + 1. Kaydır-ve-XOR döngüsü GF(2) üzerinde polinom uzun bölmesidir; bölen rolünü polinom oynar, yazmaç yürüyen kalanı tutar ve mesajın her biti bölmeyi bir adım ilerletir.
Karşınıza çıkacak neredeyse her CRC-16 bu ikisinden birini kullanır. 0x8005 ARC’de, MODBUS’ta ve USB’de görev yapıyor. 0x1021 ise bütün CCITT karmaşasını, üstüne XMODEM, KERMIT ve RFID çeşitlerini kapsıyor. Tek başına polinomu bilmek hiçbir zaman çeşidi belirlemez.
init: yazmacın başlangıç değeri
İki değer baskın: 0x0000 ve 0xFFFF. Aradaki fark göründüğünden daha önemli. Sıfırdan başlarsanız sıfır değerli bir bayt yazmacı sıfırda bırakır, dolayısıyla 00 00 01 ile 01 birebir aynı CRC değerini üretir. Yolda başına sıfır ekleyen ya da baştaki sıfırlarını kaybeden bir mesaj kontrolden geçer. 0xFFFF ile başlamak bu kör noktayı ortadan kaldırır; Modbus, CCITT-FALSE ve USB’nin hepsinin bunu seçmesinin nedeni de budur.
refin ve refout: bayt sırası değil, bit sırası
refin, her girdi baytının sekiz bitini yazmaca girmeden önce ters çevirir. refout, son XOR’dan önce nihai yazmacı ters çevirir. Veriyi LSB önce dışarı kaydıran donanım bu yansıtmaları bedavaya elde eder; bu yüzden yansıtmalı çeşitler çoğunlukla seri protokollerden çıkmış olanlardır.
En sık endianness ile karıştırılan parametre çifti budur. Oysa endianness bambaşka bir düzeyde duruyor; 6. bölüm ikisini birbirinden ayırıyor.
xorout: son XOR
refout uygulandıktan sonra yazmaca gelen bu son XOR, CRC-16 için genellikle 0x0000 ya da 0xFFFF olur; CRC-32 ailesi 0xFFFFFFFF kullanır. Yanlış ayarlanması en kolay parametredir, çünkü buradaki bir uyuşmazlık başka herhangi bir yerdeki uyuşmazlıktan ayırt edilemez.
width: 8, 16 ya da 32 bit
Genişlik, tespit tavanını belirler. n genişliğindeki bir CRC, n bite kadar uzanan her ardışık hata öbeğini yakalar ve rastgele bir bozulmayı yaklaşık 2^-n olasılıkla kaçırır. Bu, CRC-16 için 65.536’da 1, CRC-32 için 4,3 milyarda 1 eder.
CRC-16/XMODEM’den başlayıp her adımda tam olarak tek bir parametreyi değiştirerek, standart sonda girdisi 123456789 üzerinde:
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
Tek bir bayrağın dönmesi bambaşka bir çıktı veriyor. CRC’de “yakın” diye bir kavram yok. İki sonuç ya birebir tutar ya da girdilerin birbirinden ne kadar uzak olduğu konusunda size hiçbir şey söylemez; bu yüzden uyuşmayan bir değere bakarak nedeni yerelleştiremezsiniz. İç döngüde XOR ve kaydırmadan başka bir şey yok; bit düzeyinde işlemler için eksiksiz rehber bu operatörlerin kendisini anlatıyor, bu yazı ise onları bildiğinizi varsayıyor.
3. “CCITT” kötü bir ad
Eylül 2026’da RevEng CRC kataloğunda 16 bit genişliğinde 31 ayrı CRC tanımı var ve bunlardan üçü CCITT etiketi taşıyor. Bu üçünün hiçbiri diğeriyle uyuşmuyor. Aşağıdaki dört satır aynı polinomu ve aynı girdiyi paylaşıyor, birbiriyle ilgisiz dört sonuca varıyor:
| Yaygın ad | Katalog adı | check | init | refin/refout | xorout |
|---|---|---|---|---|---|
| CCITT-FALSE | CRC-16/IBM-3740 | 0x29B1 | 0xFFFF | false | 0x0000 |
| XMODEM | CRC-16/XMODEM | 0x31C3 | 0x0000 | false | 0x0000 |
| “gerçek” CCITT | CRC-16/KERMIT | 0x2189 | 0x0000 | true | 0x0000 |
| — | CRC-16/MCRF4XX | 0x6F91 | 0xFFFF | true | 0x0000 |
Tarihçesi kısa ve pek işe yaramıyor. Katalog, CRC-16/KERMIT’i CRC-CCITT ve CRC-16/CCITT-TRUE takma adlarıyla listeliyor; o çeşit yansıtmalı. init değeri 0xFFFF olan yansıtmasız bir uygulama da CCITT adı altında geniş biçimde dolaşıma girdi; kataloğun “CCITT-FALSE”u CRC-16/IBM-3740’ın takma adı olarak kaydetmesinin nedeni bu. XMODEM ikisinin arasında duruyor: aynı polinom, yansıtma yok, init sıfır.
Yani bir datasheet CCITT diyorsa, size polinomun 0x1021 olduğunu söylemiş ve başka hiçbir şey söylememiştir. Elinizde hâlâ dört aday var ve yanlışını seçmeniz size doğrusu kadar makul görünen bir değer verir.
Ad değil, parametre yazın. Protokol belgenize poly=0x1021, init=0xFFFF, refin=false, refout=false, xorout=0x0000 satırını koymak bir satır sürer ve soruyu kalıcı olarak kapatır. “CRC-16/CCITT” yazmak hiçbir şeyi kapatmaz.
4. Elinizdeki CRC-16 çeşidini nasıl belirlersiniz
Katalog bu işi bir parmak iziyle çözüyor. Her kayıt bir check değeri yayımlıyor: 123456789 dizisinin dokuz ASCII baytının CRC değeri. Önünüzdeki uygulamadan bu diziyi geçirin ve çıkan sonucu tablodan arayın.
| Çeşit | 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 (gerçek 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 |
Şaşırtıcı sayıda karşılaştırmayı batıran bir ayrıntı var: 123456789 demek, 31 32 33 34 35 36 37 38 39 baytları demek; 123456789 sayısı da değil, null ile sonlandırılmış bir dize de değil. Diliniz fonksiyona geniş karakterli bir dize veriyor ya da sonuna bir sonlandırıcı ekliyorsa, farklı bir girdi üzerinde hesap yapıyorsunuz demektir ve tablodaki her satır ıskalar. ASCII dışı payload’lar ikinci bir tuzak ekliyor: aynı metnin UTF-8 kodlanmış hâli ile Windows-1252 kodlanmış hâli iki farklı bayt dizisidir, dolayısıyla iki farklı CRC verir. ASCII tablosu ve dönüştürücü her karakterin arkasındaki baytı gösteriyor; bu soruyu bir bakışta kapatabilirsiniz.
check değeri hiçbir satırla eşleşmiyorsa, özel bir polinomdan şüphelenmeden önce sıkıcı ihtimalleri eleyin:
- Sonucu hattan ters sırayla okuyor olabilirsiniz.
- Gönderen taraf hesaba bir adres baytını, bir uzunluk baytını ya da CRC alanının kendisini katıyor veya dışarıda bırakıyor olabilir.
initüreticiye özgü olabilir, yani ne0x0000ne de0xFFFF. Tescilli sayaç protokollerinde bu gerçekten görülür ve değer genellikle bir dipnotun içine gömülüdür.
Parametreleri kaba kuvvetle bulma
Üretici firma söylemiyorsa ve firmware’lerini de okuyamıyorsanız, karşılığında tek bir şey isteyin: yakalanmış bir çerçeve ve cihazlarının o çerçeve için ürettiği CRC. Gerisi sayma işi. İki polinom, iki init değeri, birbirinden bağımsız refin ile refout ve iki xorout değeri toplam 32 kombinasyon eder; bu kadarı hiç sayılır:
target = 0x4B37 # uygulamalarının döndürdüğü değer
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
Tek isabet ve o da CRC-16/MODBUS. 123456789 yerine gerçek bir çerçeve verin; aynı 32 yollu tarama, doğru CRC değerini bildiğiniz her mesaj için işe yarar. Tek bir örnekte birden fazla kombinasyon ayakta kalırsa ikinci bir çerçeve çalıştırıp sonuçları kesiştirin.
5. Uygulamada Modbus RTU
Modbus RTU, CRC-16/MODBUS kullanır: polinom 0x8005, init 0xFFFF, girişte ve çıkışta yansıtma, son XOR yok. Altı baytlık isteğimiz için CRC değeri 0xCDC5 ve tamamlanmış çerçeve şöyle:
01 03 00 00 00 0A C5 CD
Hat sırası, değeri yazma sıranızın tersidir
Değer 0xCDC5. Çerçeveye eklenen baytlar C5 CD. Modbus, CRC’nin önce düşük baytını şart koşar; bu, onaltılık sayıyı okuduğunuz sıranın tam tersi ve insanları sürekli yanıltıyor. Aynı çerçevedeki diğer bütün çok baytlı alanlar, şu 00 0A register sayısı dahil, big-endian. Tek istisna CRC.
Bunun işe yarar bir yan etkisi var. CRC-16/MODBUS’u, CRC baytları dahil olmak üzere bütün çerçeve üzerinde hesaplayın; sonuç şu olur:
0x0000
Alıcının doğrulama rutininin tamamı bundan ibaret. Sondaki iki baytı ayırıp takas etmenize ve yerelde hesapladığınız bir değerle karşılaştırmanıza gerek yok: gelen her şey üzerinde CRC’yi çalıştırın, sıfır olup olmadığına bakın. Adım sayısı azaldıkça baytları yanlış sırayla çevirebileceğiniz yer de azalır.
Modbus dokümantasyonu neden 0xA001 gösteriyor
Neredeyse hangi Modbus uygulamasını açarsanız açın, kaynaktaki sabit 0x8005 değil 0xA001 olur. İkisi de doğru. 0xA001, 0x8005 değerinin 16 biti ters çevrilmiş hâlidir ve algoritmanın yansıtmalı biçimine aittir; o biçimde yazmaç sola değil sağa kayar, girdi baytlarının tek tek ters çevrilmesine de gerek kalmaz. İki uygulama birebir aynı çıktıyı üretir, yalnızca içleri farklıdır. Kaynak kodda geçen 0xA001, yansıtmalı bir CRC-16 uygulamasının güvenilir işaretidir.
Trafik kayıtlarında bir tuzak daha var. Modbus ASCII ayrı bir çerçeveleme; her baytı, baştaki bir 3A (:) ile sondaki 0D 0A arasında iki onaltılık karakter olarak taşır ve CRC yerine LRC kullanır. Kaydınız 01 03 beklediğiniz yerde 3A 30 31 30 33 gösteriyorsa ASCII modundasınız ve hiçbir CRC çeşidi asla tutmayacak. ASCII tablosu bu baytları doğrudan karakterlere geri eşliyor.
Aynı algoritmanın C hâli
Modbus firmware’i yukarıdaki Python modelini neredeyse hiç kullanmaz. Doğrudan yansıtmalı biçimi kullanır: sağa kaydırır ve 0xA001 ile XOR’lar:
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;
}
01 03 00 00 00 0A çerçevesiyle beslendiğinde bu fonksiyon 0xCDC5 döndürüyor; Python motorunun ürettiği değerin aynısı. 123456789 check dizisi ise 0x4B37 veriyor. İkisi de Apple clang 21 altında çalıştırıldı ve 4. bölümdeki tabloyla bit bit tutuyor.
6. refin/refout endianness değildir
Bu ikisi farklı düzeylerde yaşıyor ve aralarındaki karışıklık pahalıya patlıyor, çünkü Modbus ikisini aynı anda barındırıyor.
Endianness, çok baytlı bir değerin içindeki baytlarla ilgilidir: 0xCDC5 değeri CD C5 olarak mı yoksa C5 CD olarak mı saklanıyor veya iletiliyor. Baytın içinde hiçbir şey kımıldamaz. big-endian ile little-endian yazısının baştan sona anlattığı düzey bu; burada tekrar etmeyeceğiz.
Yansıtma ise tek bir baytın içindeki bitlerle ilgilidir. refin, her baytın sekiz bitini yazmaç onu görmeden önce ters çevirir: bit 0, bit 7 olur. Bayt mesajdaki yerini korur. İki ayardan hiçbiri diğerini etkilemez.
Bir Modbus çerçevesinde ikisi de, birbirinden bağımsız biçimde, aynı anda gerçekleşiyor:
- Algoritmanın içinde
refinverefouttrue, yani bitler baytların içinde ters çevriliyor. - Hatta ise tamamlanmış CRC önce düşük bayt gelecek şekilde ekleniyor; bu, protokolün verdiği bir bayt sırası kararı.
Bir bayt sırası sorununu “düzeltmek” için yansıtmayı kapatırsanız bambaşka bir çeşide geçersiniz; bir yansıtma uyuşmazlığını telafi etmek için çerçevenin sondaki baytlarını takas ederseniz de artık başka bir biçimde yanlış olan bir değer elde edersiniz. Teşhisi teker teker koyun: önce yalnızca algoritmayla check değerini doğru tutturun, ardından çerçeve düzenine geçin.
7. CRC-32’ye karşı CRC-16: hangisini kullanmalısınız?
CRC-32’nin de CRC-16 ile aynı sorunu var, yalnızca daha az göze batıyor; çünkü tek bir çeşit o kadar baskın ki geliştiricilerin çoğu başkalarının varlığını hiç öğrenmiyor.
| Çeşit | 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, zlib.crc32 fonksiyonunun hesapladığı çeşittir ve yığının web tarafında her yerdedir. Zip onu merkezî dizinde her kayıt için ayrı ayrı saklar; her PNG chunk’ı da chunk türünü ve verisini kapsayan böyle bir değerle biter. Ethernet’in çerçeve kontrol dizisi, sunucunuzun gönderdiği her çerçevenin sonunda aynı parametre kümesini kullanır. BZIP2 ise aynı polinomun yansıtmaları kapatılmış hâli ve ISO-HDLC ile hiçbir ortak yanı olmayan bir değer üretiyor.
CRC-16 de aynı mahallede karşınıza çıkıyor: Redis Cluster bir anahtarı 16.384 slotundan birine CRC16(key) mod 16384 ile yönlendiriyor; aynı hash tag’ini taşıyan anahtarların aynı düğüme düşmesinin nedeni de bu.
CRC-32C donanım piyangosunu neden kazandı
CRC-32C, depolama ve ağ protokollerinin gönderdiği kısa bloklarda daha iyi hata tespiti sağlayan farklı bir polinom kullanıyor. Bu ona iSCSI’yi, ext4 metadata checksum’larını, SCTP’yi ve Btrfs’i kazandırdı. Ardından Intel onu silikona koydu: SSE4.2’nin crc32 komutu doğrudan CRC-32C hesaplıyor ve bu da onu modern x86 üzerinde fiilen bedava bir bütünlük kontrolüne çeviriyor. Bugün yeni kod için bir CRC seçiyorsanız ve uyumluluk kısıtınız yoksa, seçeceğiniz bu.
Bunların hiçbiri, indirilen bir dosyayı doğrulamaya yarayan bir hash değil. Bir dosyanın sağlam ulaştığını teyit edecek bir checksum istediğinizde tanıdık araç MD5 özet üretici; MD5 ile SHA-256 karşılaştırması ise hangi iş için hangi özete güveneceğinizi anlatıyor. Bir CRC “bu bozuldu mu” sorusunu yanıtlar; kriptografik bir hash “bu, beklediğim içeriğin ta kendisi mi” sorusunu.
8. CRC kurcalamayı engellemez
Aşağıda anlamları birbirinin tam zıddı olan, CRC-32 değerleri aynı çıkan iki JSON mesajı var:
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
Aynı ikisi üzerinde SHA-256:
A -> a83b90f5e3f21dd32039e0e693a8b15864eda83e258c115deeee50a60c09ae23
B -> f9319ee0507d719c7260535dff33df721ddd9c0e1857690f3d8e02f92601b742
Sondaki baytları kaba kuvvetle aramadık, cebirle çözdük. CRC doğrusal bir fonksiyondur ve bir mesajın sonuna dört bayt eklemek, CRC-32 çıktısı üzerine birebir örten bir eşleme kurar; dolayısıyla herhangi bir mesaj ve herhangi bir hedef değer için sizi oraya götüren tam olarak tek bir dört baytlık sonek vardır ve onu bulmak aritmetikten ibarettir.
Çözülen dört bayt 46 C9 6E 0B, hello world metninin sonuna eklendiğinde:
CRC-32(b'hello world' + 46 C9 6E 0B) = 0xDEADBEEF target 0xDEADBEEF MATCH
Yani payload’unuzu değiştirebilen bir saldırgan, CRC’nizi de sabit zamanda ve hiçbir şey aramasına gerek kalmadan düzeltebilir. Mesajın başına bir sır eklemek onu kurtarmaz: uzunluğu koruyan bir değişiklikte CRC’ye uygulanacak düzeltme yalnızca değişen bitlere bağlıdır, dolayısıyla sırrı hiç bilmeden hesaplanabilir. WEP’i kıran saldırının biçimi tam olarak budur.
CRC, rastgele olan ve bir amaç gütmeyen iletim gürültüsüne karşı korur. Bir düşman bunların ikisi de değildir ve ona karşı CRC size hiçbir şey vermez. Gereksinim bütünlük değil de kimlik doğrulama olduğunda anahtarlı bir yapı gerekir: HMAC üretici herhangi bir payload ve anahtar üzerinde bunu üretiyor, webhook imza doğrulaması neden başarısız oluyor yazısı da bunu gerçek bir endpoint’e bağlarken insanları tökezleten noktaları adım adım anlatıyor.
9. SSS
CRC-16/CCITT ile CRC-16/CCITT-FALSE aynı şey mi?
Hayır, CRC-16/CCITT-FALSE ile CRC-16/CCITT farklı çeşitlerdir. CCITT-FALSE aslında CRC-16/IBM-3740’tır: init 0xFFFF, yansıtmasız, check değeri 0x29B1. Düz CCITT dendiğinde genellikle kastedilen çeşit ise CRC-16/KERMIT’tir: init 0x0000, yansıtmalı, check 0x2189. 0x1021 polinomunu paylaşırlar, başka hiçbir konuda anlaşmazlar.
Çevrimiçi bir hesaplayıcı neden cihazımla aynı sonucu vermiyor?
Neredeyse her zaman farklı parametreler yüzünden. Araç bir çeşidi varsayılan alıyordur, cihaz başka birini uyguluyordur. 123456789 ASCII baytlarını ikisinden de geçirin, çıkan iki check değerini 4. bölümdeki tabloyla karşılaştırın; uyuşmayan parametre genellikle bir dakikadan kısa sürede kendini ele verir.
Modbus CRC’nin düşük baytını neden başa koyuyor?
Şartname öyle dediği için; üstelik bu, çerçevede böyle davranan tek alan. Register adresleri ve sayıları big-endian, sondaki CRC ise değil. Baytları kendiniz yeniden sıralamak yerine CRC-16/MODBUS’u o iki bayt dahil bütün çerçeve üzerinde hesaplayın ve sonucun 0x0000 olup olmadığına bakın.
refin ile refout tam olarak neyi ters çeviriyor?
Baytın içindeki bitleri; asla mesajın içindeki baytları değil. refin, her girdi baytının sekiz bitini işlenmeden önce ters çevirir; refout, son XOR’dan önce nihai yazmacı ters çevirir. İkisi de endianness’tan bağımsızdır; endianness ise çok baytlı bir değerin hatta nasıl dizildiğini yönetir.
CRC-16 mı kullanmalıyım, CRC-32 mi?
CRC-16 rastgele bir bozulmayı kabaca 65.536 kezde bir kaçırır, CRC-32 ise 4,3 milyarda bir. Birkaç düzine baytlık kısa seri çerçeveler için CRC-16 fazlasıyla yeterli ve zaten çoğunlukla protokolün dayattığı seçenek. Dosyalar, ağ çerçeveleri ve birkaç kilobayttan büyük her şey için CRC-32 kullanın.
CRC’yi API imzası olarak kullanabilir miyim?
Hayır, bir CRC API imzası işlevi göremez. CRC doğrusaldır; payload’u değiştiren herkes eşleşen bir değeri yeniden hesaplayabilir ve seçilmiş dört baytı sona eklemek, adını verdiğiniz her CRC-32 hedefine ulaştırır. İmzalar gizli bir anahtar ve doğrusal olmayan bir yapı ister. SHA-256 ile HMAC kullanın.
Bir CRC değerinden orijinal veri geri elde edilebilir mi?
Hayır, bir CRC değerinden orijinal veri geri elde edilemez. CRC-16 herhangi bir girdiyi 16 bite sıkıştırır, dolayısıyla her değeri sonsuz sayıda mesaj paylaşır. Yine de ters yön saldırganlar için hâlâ işe yarıyor: verilen bir hedef değere karşılık onu üreten bir mesaj kurabilirsiniz ve bir CRC’nin hiçbir şeyi doğrulamamasının nedeni tam olarak bu.
Üretici belgesinde yalnızca “CRC-16” yazıyor. Parametreleri nasıl kesinleştiririm?
Yakalanmış bir çerçeveyle birlikte cihazlarının o çerçeve için hesapladığı CRC değerini isteyin, sonra 4. bölümdeki 32 kombinasyonluk taramayı bu çift üzerinde çalıştırın. Birden fazla parametre kümesi ayakta kalırsa ikinci bir çerçeveyle tekrarlayın ve kesişimi alın. İki örnek neredeyse her zaman belirleyici oluyor.