사전 체크섬
개념

체크섬

gabury1고친 사람 github-actions[bot]

체크섬은 데이터가 옮겨지거나 보관되는 동안 망가졌는지 알아채게 해 줍니다. 보내는 쪽이 데이터로 짧은 값을 계산해 함께 붙입니다. 받는 쪽은 같은 계산을 다시 해서 붙어 온 값과 견줍니다. 두 값이 다르면 그 데이터를 믿지 않고 버립니다.

쉽고 빠른 이해

체크섬은 데이터에 붙여 보내는 짧은 확인 값입니다. 네트워크 패킷의 머리 부분에도 붙고, 내려받는 파일 옆에도 적혀 있습니다.

전선이나 디스크에서는 비트가 가끔 뒤집힙니다. 이걸 모르고 쓰면 틀린 값으로 계산하거나 깨진 파일을 엽니다. 원본을 통째로 다시 받아 비교하는 대신 짧은 값 하나만 맞춰 봅니다.

어떻게 쓰나:

  1. 보내는 쪽이 데이터로 값을 계산해 붙입니다
  2. 받는 쪽이 받은 데이터로 같은 계산을 합니다
  3. 두 값이 다르면 데이터를 버리고, 필요하면 다시 받습니다

대가도 있습니다. 망가진 줄은 알아도 어디가 망가졌는지는 모릅니다. 누군가 일부러 데이터와 값을 함께 바꾸면 막지 못합니다.

상세

이 절은 체크섬이 무엇을 잡으려고 만들어졌는지에서 시작합니다. 그다음 가장 단순한 계산부터 네트워크가 쓰는 두 방식까지 다룹니다.

뒤쪽에는 쓰임 둘이 나옵니다. 하나는 패킷마다 붙는 체크섬입니다. 다른 하나는 오래 보관하는 파일에 붙는 체크섬입니다. 끝에서는 체크섬이 못 하는 일과 암호학적 해시와 가르는 선을 짚습니다.

오는 길에 비트가 뒤집힌다

데이터는 결국 0과 1의 줄입니다. 전선을 지나는 전기 신호에 잡음이 끼면 1이 0으로 읽힐 수 있습니다. 디스크나 메모리에 오래 둔 비트가 저절로 바뀌기도 합니다.

이런 오류는 드물지만 조용합니다. 받는 프로그램은 뒤집힌 비트를 보고도 멀쩡한 데이터처럼 읽습니다. 계좌 번호의 숫자 하나가 바뀌어도 형식은 여전히 맞기 때문입니다.

그래서 받는 쪽이 스스로 확인할 방법이 필요합니다. 데이터에서 계산한 값을 같이 보내면 받는 쪽이 계산을 되풀이해 볼 수 있습니다. 이 확인 값이 체크섬입니다. 이렇게 오류를 알아채는 일을 오류 검출이라고 합니다.

보내는 쪽과 받는 쪽이 하는 일

두 쪽은 어떤 계산을 쓸지 미리 약속합니다. 보내는 쪽은 그 계산으로 값을 만들어 데이터 옆에 붙입니다. 받는 쪽은 데이터만 떼어 같은 계산을 한 뒤 두 값이 같은지 확인합니다.

sequenceDiagram
    participant 보내는쪽 as 보내는 쪽
    participant 받는쪽 as 받는 쪽
    보내는쪽->>보내는쪽: 데이터로 체크섬을 계산한다
    보내는쪽->>받는쪽: 데이터와 체크섬을 함께 보낸다
    받는쪽->>받는쪽: 받은 데이터로 다시 계산한다
    Note over 받는쪽: 두 값이 다르면 데이터를 버린다

그림에서 받는 쪽이 하는 일은 확인뿐입니다. 망가진 데이터를 고치지는 않습니다. 버린 뒤 다시 보내 달라고 할지는 그 위에서 도는 프로토콜이 정합니다.

가장 단순한 체크섬

바이트를 모두 더하는 방식이 가장 단순합니다. 합이 255를 넘으면 256으로 나눈 나머지만 남겨 한 바이트에 담습니다. 바이트 셋을 보내는 경우로 따라갑니다.

12 + 34 + 56   // 102
13 + 34 + 56   // 103
56 + 34 + 12   // 102

첫 줄이 보낸 데이터의 체크섬입니다. 둘째 줄은 첫 바이트의 비트 하나가 뒤집힌 경우입니다. 합이 달라지므로 오류가 드러납니다.

셋째 줄은 바이트 순서가 뒤바뀐 경우입니다. 데이터는 틀렸습니다. 그런데 합이 같아서 오류를 놓칩니다. 더하기는 순서를 모르기 때문입니다. 아래에서 볼 나눗셈 방식이 이 약점을 메웁니다.

인터넷 체크섬

TCP(Transmission Control Protocol, 전송 제어 프로토콜)와 UDP(User Datagram Protocol, 사용자 데이터그램 프로토콜) 헤더에는 인터넷 체크섬이 들어갑니다. 바이트 하나가 아니라 16비트씩 끊어서 더합니다. 덧셈만 하므로 모든 패킷마다 돌려도 부담이 적습니다.

16비트 두 개를 더하는 경우로 따라갑니다. 값은 16진수로 적습니다. 16진수 한 글자가 4비트라 네 글자가 16비트입니다.

첫 단계는 덧셈입니다. 더하다가 16비트를 넘친 자리올림은 버리지 않고 맨 아래에 다시 더합니다. 이렇게 더하는 법을 1의 보수 덧셈이라고 합니다.

0xF000 + 0x2000   // 0x11000
0x1000 + 1        // 0x1001

첫 줄의 합은 16비트를 넘쳐 다섯 글자가 됐습니다. 둘째 줄은 넘친 1을 떼어 아래 네 글자에 다시 더합니다.

둘째 단계는 합의 비트를 모두 뒤집는 것입니다. 코드의 ~ 가 비트를 뒤집는 연산입니다. 0은 1이 되고 1은 0이 됩니다. 이렇게 뒤집은 값을 그 수의 1의 보수라고 합니다. 이 값이 체크섬입니다.

~0x1001           // 0xEFFE

받는 쪽은 체크섬까지 넣어서 같은 방식으로 모두 더합니다. 오류가 없으면 합의 비트가 전부 1이 됩니다.

0x1001 + 0xEFFE   // 0xFFFF

인터넷 체크섬도 더하기라 16비트 덩이의 순서가 바뀌면 못 잡습니다. 대신 계산이 빠릅니다. 헤더의 값 하나가 바뀌었을 때 전부 다시 계산하지 않고 고칠 수도 있습니다. 더하기로 만든 값이라 옛 값만큼 빼고 새 값만큼 더하면 되기 때문입니다.

CRC

CRC(Cyclic Redundancy Check, 순환 중복 검사)는 더하기 대신 나눗셈의 나머지를 씁니다. 데이터 전체를 아주 긴 이진수 하나로 보고, 미리 약속한 수로 나눕니다. 그 나머지가 체크섬입니다.

나눗셈의 나머지는 비트가 어디에 있는지에 따라 달라집니다. 그래서 순서가 바뀐 오류도 잡습니다. 잡음 한 번에 이웃한 비트 여러 개가 함께 뒤집히는 오류도 잘 잡습니다. 체크섬 비트 수보다 짧은 구간에 몰린 오류는 하나도 놓치지 않습니다.

나눗셈이라 인터넷 체크섬보다 연산이 많습니다. 그 대신 비트 단위 연산으로 풀리므로 네트워크 카드 같은 하드웨어가 직접 계산하기 좋습니다.

그래서 이더넷은 CRC 를 씁니다. 이더넷이 한 번에 보내는 데이터 덩어리를 프레임이라고 합니다. 프레임 맨 끝에는 꼬리처럼 붙는 칸, 곧 트레일러가 있고 여기에 32비트 CRC 가 들어갑니다.

패킷마다 붙는 체크섬

패킷 하나가 목적지에 닿는 동안 여러 계층이 저마다 체크섬을 봅니다. 아래 계층은 한 구간의 전선만 지킵니다. 위 계층은 출발지에서 목적지까지를 지킵니다.

IPv4(Internet Protocol version 4, 인터넷 프로토콜 4판)는 헤더에만 체크섬을 붙입니다. 헤더에 든 TTL(Time To Live, 남은 거쳐 갈 횟수)은 라우터를 지날 때마다 1씩 줄어듭니다. 그래서 라우터마다 체크섬을 고쳐 적어야 합니다. 이때 앞의 인터넷 체크섬 절에서 본 성질을 씁니다. 헤더 전체를 다시 더하지 않고 TTL 이 바뀐 만큼만 체크섬에 반영합니다.

IPv6(Internet Protocol version 6, 인터넷 프로토콜 6판)는 헤더 체크섬을 뺐습니다. 아래의 이더넷 CRC 와 위의 TCP · UDP 체크섬이 이미 지키고 있어 겹친다고 보았습니다. 라우터가 패킷마다 다시 계산하는 일도 함께 사라졌습니다.

그 대신 IPv6 위에서는 UDP 체크섬을 빼먹을 수 없습니다. IPv4 위의 UDP 는 체크섬 칸을 0으로 두어 「계산하지 않았다」고 표시할 수 있었습니다. IPv6 에서는 헤더 체크섬이 없으니 UDP 체크섬마저 빠지면 아무도 확인하지 않게 됩니다.

세 계층의 체크섬을 모아 그리면 아래와 같습니다. 화살표는 위 계층에서 아래 계층으로 내려가는 방향입니다. 칸마다 그 체크섬이 지키는 범위를 적었습니다.

flowchart TD
    A["TCP · UDP 체크섬 · 출발지에서 목적지까지"] --> B["IPv4 헤더 체크섬 · 헤더만 · 라우터마다"]
    B --> C["이더넷 CRC · 이웃한 두 장비 사이 한 구간"]

의사 헤더

TCP · UDP 체크섬은 자기 헤더와 데이터만 계산하지 않습니다. 그 아래 IP(Internet Protocol, 인터넷 프로토콜) 헤더에서 출발 주소와 도착 주소 같은 값을 뽑아 앞에 붙인 뒤 함께 계산합니다. 이렇게 계산에만 쓰고 보내지는 않는 머리 조각을 의사 헤더라고 부릅니다.

의사 헤더가 필요한 까닭은 주소가 망가지는 경우 때문입니다. 도착 주소의 비트가 뒤집히면 패킷이 엉뚱한 컴퓨터에 닿습니다. 받은 컴퓨터가 자기 주소로 체크섬을 계산하면 값이 맞지 않으므로 그 패킷을 버립니다.

보관한 파일을 지키는 체크섬

체크섬은 전송에만 쓰지 않습니다. 오래 보관하는 파일도 디스크 안에서 조금씩 상할 수 있습니다. 파일을 저장할 때 체크섬을 계산해 메타데이터로 함께 적어 둡니다.

나중에 파일을 열거나 정기 점검을 돌릴 때 체크섬을 다시 계산합니다. 적어 둔 값과 다르면 그 파일은 저장한 뒤 바뀐 것입니다. 이렇게 파일이 처음 그대로인지 확인하는 성질을 무결성이라고 부릅니다. 복사본이 따로 있으면 깨진 쪽을 멀쩡한 복사본으로 바꿉니다.

내려받는 파일에도 같은 방법을 씁니다. 배포하는 쪽이 파일 옆에 체크섬을 적어 둡니다. 받은 사람은 자기 손의 파일로 다시 계산해 비교합니다.

체크섬이 못 하는 일

체크섬은 오류가 있다는 것만 알려 줍니다. 어느 비트가 틀렸는지는 모르므로 고치지 못합니다. 틀린 비트를 찾아 고치기까지 하려면 오류 정정 부호처럼 값을 더 많이 붙이는 방법을 써야 합니다.

체크섬이 맞았다고 오류가 없다고 장담할 수도 없습니다. 체크섬은 데이터보다 훨씬 짧으므로 서로 다른 데이터가 같은 값을 낼 수 있습니다. 우연한 오류가 마침 같은 값을 만들 확률이 낮을 뿐입니다.

가장 큰 한계는 일부러 바꾸는 사람입니다. 체크섬 계산법은 누구나 압니다. 데이터를 바꾼 사람이 체크섬도 새로 계산해 바꿔 넣으면 받는 쪽은 알아채지 못합니다.

암호학적 해시와 가르기

해시 함수는 데이터를 짧은 값으로 줄이는 함수입니다. 그 가운데 속이려는 사람까지 막도록 만든 것이 암호학적 해시 함수입니다. 대표가 SHA-256(Secure Hash Algorithm, 안전한 해시 알고리즘)입니다.

암호학적 해시 함수는 원하는 값이 나오도록 데이터를 꾸며 내기가 현실적으로 불가능하게 만들어졌습니다. 다만 데이터를 여러 번 뒤섞느라 연산이 많고 값이 깁니다.

체크섬 암호학적 해시
막으려는 것 우연히 뒤집힌 비트 누군가 일부러 바꾼 내용
계산 덧셈이나 나눗셈 한 번 여러 번 뒤섞기
값의 길이 16비트 · 32비트 수백 비트
대표 인터넷 체크섬 · CRC SHA-256

두 말이 섞여 쓰이기도 합니다. 파일 옆에 적힌 SHA-256 값을 흔히 「체크섬」이라고 부릅니다. 이때 체크섬은 계산 방식이 아니라 「내용을 확인하는 값」이라는 쓰임을 가리킵니다.

어느 쪽이든 파일과 값을 같은 곳에서 받으면 둘이 함께 바꿔치기될 수 있습니다. 값 자체를 믿을 수 있는지는 전자 서명 같은 다른 장치가 맡습니다.

관련 항목

체크섬을 계산하는 방식

인터넷 체크섬 · CRC · 1의 보수 · 패리티 비트 · Adler-32 · Fletcher 체크섬

체크섬 칸을 헤더에 두는 프로토콜

TCP · UDP · IPv4 · IPv6 · ICMP · 이더넷

체크섬이 붙는 데이터 단위와 그 부품

패킷 · 프레임 · 헤더 · 트레일러 · 의사 헤더 · 페이로드 · TTL

체크섬이 지키는 성질과 그 쓰임

오류 검출 · 무결성 · 메타데이터 · 비트 부패 · 데이터 스크러빙

체크섬보다 더 멀리 가는 확인 수단

해시 · 해시 함수 · 암호학적 해시 함수 · SHA-256 · MD5 · 메시지 인증 코드 · 전자 서명 · 오류 정정 부호

다른 이름: checksum · 검사합 · 검사값