⚡ [클래식] RC4 키 스케줄의 약점 — WEP를 무너뜨린 '약한 IV' 한 줌

2026-10-21 · 카테고리: Research (클래식 보안 논문 · 스트림 암호 · RC4 · WEP/802.11 · 키 스케줄 · 무선 보안)

논문 정보

제목: Weaknesses in the Key Scheduling Algorithm of RC4
저자: Scott Fluhrer (Cisco Systems), Itsik Mantin, Adi Shamir (Weizmann Institute of Science)
출처: Selected Areas in Cryptography (SAC) 2001, LNCS Vol. 2259, pp. 1–24 (Springer) · 2001년 8월 공개
분야: 스트림 암호 암호분석 · 키 스케줄(KSA) · related-key 공격 · 무선랜 보안(WEP) · 프로토콜 설계
인용: OpenAlex 기준 1,043회 (LNCS 2001 레코드)
원문: Springer (DOI 10.1007/3-540-45682-1_2) · Semantic Scholar · FMS 공격 개요

왜 이 논문인가 — 무너진 것은 '수학'이 아니라 '조립'이었다

WEP(Wired Equivalent Privacy)는 1997년 IEEE 802.11 표준의 일부로 확정된 무선랜 암호화 방식입니다. 이름부터가 야심적이었습니다. "유선과 동등한(equivalent) 프라이버시". 그리고 실제로 그 이름값을 정확히 했습니다 — 유선과 동등하게, 즉 전혀 안전하지 않았습니다.

2001년 8월, 시스코의 Scott Fluhrer와 와이즈만 연구소의 Itsik Mantin·Adi Shamir는 이 실패가 구현 버그나 짧은 키 때문이 아니라는 것을 보여줍니다. RC4라는 암호 자체도, 40비트라는 키 길이도 아닙니다. 문제는 RC4의 키 스케줄 알고리즘(KSA)에 키를 넣는 방식 — 특히 공개된 IV를 비밀 키 앞에 그대로 이어 붙이는 그 한 줄이었습니다. IV를 키의 일부로 쓰는 순간, 공격자는 같은 키를 자기가 고른 변형으로 수만 번 사용할 수 있게 됩니다. related-key 공격의 무대가 스스로 열린 셈입니다.

이 논문의 진짜 교훈은 "RC4가 약하다"가 아닙니다. 암호 프리미티브가 안전해도, 그 프리미티브에 키를 공급하는 방식(key schedule)이 공격면이 된다는 것입니다. 2026년의 AEAD·논스 설계에서도 그대로 반복되는 교훈입니다.

배경 — WEP가 조립한 세 부품과 그 사이의 틈

WEP의 설계는 단순합니다. 부품 세 개를 이어 붙였습니다.

부품역할설계자의 기대실제
RC4 (스트림 암호)기밀성 — 평문 ⊕ 키스트림"빠르고 검증된 스트림 암호"프리미티브 자체는 이 논문의 표적이 아님
24비트 IV패킷마다 다른 키스트림"충돌은 일어나지 않는다"224 = 16,777,216 — 생일 한계로 5,000패킷이면 절반이 겹침
CRC-32 (ICV)무결성"변조를 탐지한다"선형 함수 — 암호학적 인증이 아님, 비트 플립에 그대로 반응

첫 번째 균열 — 24비트 IV, 5,000패킷이면 절반이 겹친다

스트림 암호의 절대 규칙은 하나입니다. 같은 키스트림을 두 번 쓰지 말 것. 두 번 쓰면 C₁ ⊕ C₂ = P₁ ⊕ P₂가 되어 암호가 통째로 사라집니다(두 번 쓰는 일회용 패드, two-time pad).

즉 WEP는 "IV가 충분히 크다"는 가정 하나에 기밀성 전체를 걸었고, 그 가정은 트래픽이 조금만 많아지면 무너집니다.

FMS의 핵심 — KSA의 '결정되는 앞 3스텝'에서 키 한 바이트가 샌다

IV 충돌은 기밀성의 문제입니다. FMS가 보여준 것은 더 나쁩니다. 충돌이 한 번도 없어도 키 자체를 복원할 수 있다는 것.

RC4의 키 스케줄은 256번의 스왑으로 S-box를 섞습니다.

for i in 0..255:
    j = (j + S[i] + key[i mod keylen]) mod 256
    swap(S[i], S[j])

WEP에서 key의 앞 3바이트는 공개된 IV입니다. 그래서 공격자는 KSA의 첫 3회 반복을 정확히 재현할 수 있고, 그 결과 i=3 시점의 S-box 상태를 (자기가 고른 IV에 대해) 알고 있습니다. 문제는 그다음입니다.

결과적으로 완전히 수동적인(passive) 공격입니다. 전파를 잡기만 하면, 키를 네트워크에 한 번도 던지지 않고 복원할 수 있습니다. 트래픽이 많은 네트워크라면 논문이 언급한 것처럼 1분 수준의 관찰로 충분할 수 있습니다.

두 번째 균열 — CRC-32는 무결성이 아니다

FMS는 기밀성 붕괴입니다. 그런데 WEP의 ICV는 선형 함수인 CRC-32라서, 암호학적 MAC이 하려는 일을 원리적으로 못 합니다.

실전화 — AirSnort·aircrack, 그리고 2007년의 마무리

필요 패킷(104비트 키)성공 확률
40,00050%
60,000약 80%
85,000약 95%

반응과 청구서 — WPA, 그리고 RC4의 최후

교육용 PoC — 키스트림 재사용이 왜 치명적인가 (로컬 실습 전용)

아래 코드는 실제 네트워크 공격이 아니라, 같은 IV로 두 번 암호화했을 때 무엇이 사라지는지 눈으로 확인하는 장난감 구현입니다. RC4 KSA/PRGA를 30줄로 옮기고, 가상의 두 평문을 같은 IV로 암호화한 뒤 XOR만으로 두 번째 평문이 복원되는지 봅니다.

def ksa(key: bytes) -> list:
    S = list(range(256)); j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]
    return S

def prga(S: list, n: int) -> bytes:
    i = j = 0; out = bytearray()
    for _ in range(n):
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        out.append(S[(S[i] + S[j]) % 256])
    return bytes(out)

iv, shared = b"\x01\x02\x03", b"SECRETKEY"      # IV는 평문 전송된다고 가정
ks = prga(ksa(iv + shared), 16)                 # 두 패킷이 같은 IV를 썼다면
p1 = b"HTTP/1.1 200 OK"[:16]
p2 = b"HTTP/1.1 403 NO"[:16]
c1 = bytes(a ^ b for a, b in zip(p1, ks))       # 같은 키스트림으로 두 번 암호화
c2 = bytes(a ^ b for a, b in zip(p2, ks))
print(bytes(a ^ b for a, b in zip(c1, c2)))     # = p1 ^ p2 : 암호가 사라진다

한계와 반론

그래서 무엇이 남는가

출처

목록으로 돌아가기