개발 이야기3분 읽기

두 CRC 도구가 다른 값을 내는 이유

같은 다항식을 쓰는 CRC-16 셋이 서로 다른 값을 냅니다. 초기값·반전·최종 XOR이 무엇을 하는지 정리했습니다.

장비 문서에 "CRC-16을 붙여 보내라"고 적혀 있습니다. 계산해서 보냈는데 거부됩니다.

같은 다항식, 다른 값

규격의 표준 검사 문자열 "123456789"로 여러 변종을 계산해 봤습니다.

이름                  다항식      초기값      반전   결과
CRC-16/ARC            0x8005      0x0000      예     0xBB3D
CRC-16/MODBUS         0x8005      0xFFFF      예     0x4B37
CRC-16/CCITT-FALSE    0x1021      0xFFFF      아니오  0x29B1
CRC-16/XMODEM         0x1021      0x0000      아니오  0x31C3
CRC-16/KERMIT         0x1021      0x0000      예     0x2189
CRC-32 (zlib)         0x04C11DB7  0xFFFFFFFF  예     0xCBF43926
CRC-32/BZIP2          0x04C11DB7  0xFFFFFFFF  아니오  0xFC891918

다항식 0x1021을 쓰는 셋이 전부 다른 값을 냅니다. CRC-32도 반전 여부만으로 갈립니다.

"CRC-16"이라는 이름만으로는 값이 정해지지 않습니다.

파라미터 다섯 개

CRC 하나를 특정하려면 다섯 가지가 필요합니다.

파라미터 하는 일
결과 비트 수 (16, 32 …)
다항식 나눗셈에 쓰는 값
초기값 레지스터 시작값
입출력 반전 비트 순서를 뒤집는지
최종 XOR 결과에 XOR할 값

초기값이 0이 아닌 이유가 있습니다. 초기값 0이면 앞에 붙은 0x00 바이트가 값을 바꾸지 않습니다. [0x00, 0x00, 0x41][0x41]이 같은 CRC를 냅니다. 초기값을 0xFFFF로 두면 선행 0이 구분됩니다.

반전은 하드웨어 구현에서 왔습니다. 직렬 통신은 최하위 비트부터 보내는 경우가 많아서, 시프트 레지스터가 자연스럽게 반전된 순서로 동작합니다. 소프트웨어로 옮기면서 그 순서를 재현한 것이 반전 플래그입니다.

검사 문자열이 있는 이유

CRC 규격들은 "123456789"(ASCII 9바이트)에 대한 값을 함께 적어 둡니다. 구현이 맞는지 확인하는 기준값입니다.

위 표의 값들은 전부 규격에 적힌 값과 일치합니다. 새 구현을 붙일 때 이 문자열부터 넣어 보면 파라미터가 맞는지 바로 나옵니다.

CRC는 무결성 검사이지 서명이 아니다

CRC는 선형입니다. 이 성질이 오류 검출에는 유리하고 위조 방지에는 치명적입니다.

CRC32("PAY 100") = 33BA647C
CRC32("PAY 900") = 3DA935C4
두 값을 XOR      = 0E1351B8

이 XOR 값은 두 평문의 차이만으로 계산됩니다. 키가 개입하지 않습니다.

그래서 메시지를 바꾸면서 CRC를 원하는 값으로 맞추는 것이 쉽습니다. 메시지 어딘가에 4바이트 여유만 있으면 CRC를 임의의 값으로 조정할 수 있습니다.

CRC가 잡는 것은 전송 중 발생한 잡음입니다. 연속된 비트 오류를 다항식 차수까지 확실히 검출합니다. 악의적인 변조는 잡지 못합니다. 그 자리에는 HMAC이 갑니다.

어디서 마주치나

변종
zlib·PNG·gzip·Ethernet CRC-32
Modbus RTU CRC-16/MODBUS
XMODEM 프로토콜 CRC-16/XMODEM
옛 아카이브(ARC) CRC-16/ARC
USB 패킷 CRC-5, CRC-16

임베디드 장비 문서에서 "CCITT"라고만 적혀 있으면 조심해야 합니다. CCITT-FALSE(초기값 0xFFFF, 반전 없음)와 KERMIT(초기값 0x0000, 반전)이 둘 다 CCITT 계열로 불리는데 값이 다릅니다.

확인 순서

  1. 상대 장비의 CRC 파라미터 다섯 개를 문서에서 확인합니다. 이름만으로는 부족합니다
  2. "123456789"를 넣어 기대값이 나오는지 먼저 봅니다
  3. 값이 안 맞으면 반전부터 의심합니다. 바이트 순서를 뒤집은 값이 나오는 경우가 흔합니다
  4. 결과를 전송할 때 바이트 순서(빅엔디언·리틀엔디언)를 확인합니다. 계산이 맞아도 여기서 갈립니다
  5. 변조 방지가 목적이면 CRC가 아니라 HMAC을 씁니다

tools.onuel.devCRC 계산기는 다항식·초기값·반전·최종 XOR을 직접 지정할 수 있어서, 장비 문서의 파라미터를 그대로 넣어 대조할 수 있습니다. CRC-16은 Modbus 등에서 쓰는 ARC 변종을 바로 계산하고, CRC-32는 zlib 계열입니다. 변조 방지가 필요하면 HMAC 쪽이고, 바이트를 직접 확인할 때는 Hex 덤프를 씁니다.

  • #CRC
  • #체크섬
  • #프로토콜