SMP 완전판: P-256에서 LTK까지
1권 8장은 “숫자 비교로 중간자를 막는다”까지 보여 줬다. 이 장은 LE Secure Connections 페어링에 쓰이는 함수를 하나도 빼지 않고 계산한다. 타원곡선 위의 공개 키 교환, 약속값 f4, 화면의 여섯 자리 g2, 열쇠를 뽑는 f5, 확인값 f6, 클래식과 키를 나눠 쓰는 h6·h7까지. 사양 부록 D의 샘플이 모두 디버그 키로 만들어졌다는 것도 확인한다.
- Secure Connections의 2단계(공개 키 교환 → 인증 1단계 → 인증 2단계)에서 어떤 값이 언제 오가는지 설명할 수 있다.
- f4·f5·f6·g2·h6·h7의 입력 순서와 바이트 순서를 지켜 직접 계산하고 사양 샘플과 맞출 수 있다.
- 공개 키 검증과 디버그 키가 왜 필요한지, 무엇을 열어 두는지 안다.
- CTKD로 LE의 LTK와 클래식 링크 키를 오가는 규칙(CT2)과 암호화 키 길이의 의미를 안다.
세 단계와 그 안의 함수들
SMP 페어링은 세 단계다. 1단계에서 Pairing Request/Response로 입출력 능력, OOB 유무, 인증 요구(MITM, 본딩, SC, CT2), 최대 키 길이, 나눠 줄 키를 주고받는다(1권 8장). 2단계가 이 장의 대부분이다. Secure Connections라면 양쪽이 P-256 공개 키를 주고받아 공유 비밀 DHKey를 만들고(공개 키 교환), 그 교환이 중간자에게 바꿔치기되지 않았는지 사람이나 OOB로 확인하고(인증 1단계), DHKey로 MacKey와 LTK를 뽑은 뒤 서로 그 키를 가졌다는 확인값을 교환한다(인증 2단계). 3단계에서 암호화된 링크 위로 IRK, 신원 주소 등을 나눈다.
둘이 각자 비밀 물감(개인 키)을 갖고, 모두가 아는 기본 물감(곡선의 기준점 G)에 섞어 만든 색(공개 키)을 바꿔 든다. 받은 색에 다시 자기 비밀 물감을 섞으면 둘 다 같은 색(DHKey)이 나오지만, 구경꾼은 섞인 색만 보고 비밀 물감을 뽑아낼 수 없다. 다만 가운데서 물감을 바꿔치기하는 사람이 있으면 둘은 각자 그 사람과 같은 색을 만들게 된다. 그래서 마지막에 “우리 둘이 같은 색인가”를 사람의 눈(숫자 비교)으로 확인한다.
2단계 전체: [Vol 3] Part H §2.3.5.6(공개 키 교환 §2.3.5.6.1, 숫자 비교 §2.3.5.6.2, 패스키 §2.3.5.6.3, OOB §2.3.5.6.4, 인증 2단계 §2.3.5.6.5) · 함수 정의: §2.2
P-256: 공개 키를 받으면 먼저 곡선 위인지 본다
Secure Connections는 NIST P-256 곡선(y² = x³ − 3x + b, 소수 p 위)을 쓴다. 개인 키는 256비트 정수 d, 공개 키는 기준점 G를 d번 더한 점 Q = d·G의 (x, y), DHKey는 상대 공개 키에 내 개인 키를 곱한 점의 x 좌표 32바이트다. Pairing Public Key PDU는 X와 Y를 32바이트씩, 작은 바이트부터 싣는다.
받은 공개 키는 반드시 곡선 위의 점인지 검사해야 한다(x, y가 0~p−1이고 곡선 식을 만족하는지). 검사하지 않으면 공격자가 곡선 밖의 점을 보내 상대 개인 키에 대한 정보를 조금씩 얻어 낼 수 있다는 것이 알려져 있고(2018년 공개된 취약점), 사양은 이후 이 검사를 의무로 바꿨다. 검사에 실패하거나, 두 공개 키의 X가 같으면(디버그 키 제외) “DHKey Check Failed”로 페어링을 끝낸다.
사양에는 시험 장비가 암호화된 연결을 들여다볼 수 있도록 공개된 고정 개인 키가 있다. 한쪽만 이 키를 써도 스니퍼가 DHKey를 계산할 수 있어 LTK와 모든 트래픽이 드러난다. 그래서 디버그 키를 받았는데 디버그 모드가 아니면 페어링을 거부할 수 있다(Invalid Parameters). 아래 부록 D 샘플의 U = 20b003d2…는 바로 이 디버그 공개 키의 X다. 양산 펌웨어에서 디버그 모드가 켜져 있지 않은지 점검 항목에 넣자.
P-256 공개 키 검사와 DHKey
공개 키 검증 의무와 X가 같은 경우의 실패: [Vol 3] Part H §2.3.5.6.1 · 곡선 파라미터: [Vol 2] Part H §7.6 · 디버그 키 쌍과 거부: [Vol 3] Part H §2.3.5.6.1 · 공개 키 PDU 형식: [Vol 3] Part H §3.5.6
인증 1단계: f4로 약속하고, g2로 보여 준다
응답자 B는 nonce Nb를 정한 뒤 바로 보내지 않고, 먼저 약속값 Cb = f4(PKbx, PKax, Nb, 0)를 보낸다. 그다음 A가 Na를 보내고, B가 Nb를 공개하면 A는 f4를 다시 계산해 Cb와 같은지 본다. 중간자가 Na를 본 뒤에 자기에게 유리한 Nb를 고르는 것을 막는 장치다. 숫자 비교라면 양쪽 화면에 Va = g2(PKax, PKbx, Na, Nb) mod 10⁶을 여섯 자리로 띄운다.
패스키 방식은 20라운드다. 여섯 자리 패스키(20비트)의 비트 하나를 라운드마다 약속값에 넣는다. Z = 0x80 | 그 비트. 라운드마다 새 nonce를 쓰고, 한 라운드라도 어긋나면 그 자리에서 실패한다. 중간자는 라운드마다 비트 하나만 짐작할 기회가 있고, 틀리면 들킨다. 한 번 쓴 패스키를 다시 쓰면 이전 페어링을 엿들은 사람이 비트를 이미 알 수 있으므로, 페어링마다 새 패스키를 써야 한다.
f4와 입력(Table 2.1)·Z 값: [Vol 3] Part H §2.2.6 · g2: §2.2.9 · 숫자 비교 절차: §2.3.5.6.2 · 패스키 20라운드: §2.3.5.6.3
인증 2단계: f5가 열쇠를 뽑고, f6이 확인한다
DHKey는 곡선 위 점의 좌표라서 그대로 쓰기엔 고르지 않다. f5가 이것을 두 번 걸러 쓸 수 있는 키 두 개로 만든다. 먼저 고정된 SALT로 T = AES-CMACSALT(DHKey)를 만들고, T를 키로 카운터만 다른 두 블록을 만든다. 카운터 0이 MacKey, 카운터 1이 LTK다. 주소에는 공개/임의 주소 여부가 앞 바이트로 붙는다(A1 = 00 + 6바이트 주소, 임의 주소면 01).
마지막으로 서로 Ea = f6(MacKey, Na, Nb, rb, IOcapA, A, B), Eb = f6(MacKey, Nb, Na, ra, IOcapB, B, A)를 교환한다. MacKey를 모르면 맞는 Ea·Eb를 만들 수 없으니 “같은 DHKey를 가졌다”를 증명하고, IOcap를 넣어 1단계에서 주고받은 능력값을 중간자가 바꾸지 않았음도 함께 확인한다(능력값을 깎아 Just Works로 끌어내리는 것을 막는다). 숫자 비교에서는 r = 0, 패스키에서는 r = 패스키 값, OOB에서는 r = 상대의 OOB 난수다.
SMP 함수 계산기: 부록 D 샘플을 블록까지
f5(SALT, keyID “btle”, Length 256, 주소 형식): [Vol 3] Part H §2.2.7 · f6과 입력(Table 2.2), IOcap 순서, 패스키를 r로 쓰는 법: §2.2.8 · 인증 2단계: §2.3.5.6.5 · 샘플: Appendix D.2~D.8
숫자 비교 한 번을 처음부터 끝까지
아래 시뮬레이터는 A와 B가 각자 키 쌍과 nonce를 만들고, 위의 함수들로 Cb 검사 → 여섯 자리 → LTK → Ea·Eb 검사를 실제로 계산한다. 중간자를 켜면 M이 양쪽과 따로 키를 교환한다. A 화면의 숫자는 A와 M의 공개 키로, B 화면의 숫자는 M과 B의 공개 키로 계산되므로, M이 각 구간을 아무리 정상적으로 처리해도 두 숫자는 달라진다.
숫자 비교: P-256부터 DHKey Check까지
A (개시자) 화면
B (응답자) 화면
비교를 위해: 레거시 c1과 s1
레거시 페어링은 타원곡선 없이 TK(0이나 6자리 패스키)를 키로 쓴다. c1으로 약속값을 만들고, s1으로 두 난수의 아래 8바이트씩을 이어 STK를 만든다. 공개 키가 없으니, 교환을 녹음한 사람은 TK 후보 백만 개(Just Works면 0 하나)를 차례로 넣어 c1이 맞는 값을 찾을 수 있다. 1권 8장의 결론이 이 구조에서 나온다. Secure Connections를 요구하는 설정(SC Only 모드, GAP의 LE 보안 모드 1 레벨 4)이 방어다.
c1과 예제 값: [Vol 3] Part H §2.2.3 · s1과 예제 값: §2.2.4 · LE 보안 모드 1 레벨 4: [Vol 3] Part C §10.2.1
CTKD: 한 번 페어링으로 두 전송 모두
클래식과 LE를 함께 쓰는 기기(이어폰, 차량)는 한쪽에서 Secure Connections 페어링을 하면 다른 쪽 키를 같은 강도로 유도할 수 있다. 이것이 교차 전송 키 유도(Cross-Transport Key Derivation, CTKD)다. LE의 LTK에서 클래식 링크 키를 만들 때는 중간 키 ILK를 거치고, 양쪽 모두 Pairing Request/Response의 CT2 비트를 1로 했으면 h7을, 한쪽이라도 0이면 옛 방식 h6을 쓴다.
| 방향 | CT2 = 1 (양쪽) | CT2 = 0 (한쪽이라도) |
|---|---|---|
| LTK → 링크 키 | ILK = h7(“tmp1”, LTK) → h6(ILK, “lebr”) | ILK = h6(LTK, “tmp1”) → h6(ILK, “lebr”) |
| 링크 키 → LTK | ILTK = h7(“tmp2”, LK) → h6(ILTK, “brle”) | ILTK = h6(LK, “tmp2”) → h6(ILTK, “brle”) |
키 길이도 함께 다룬다. 1단계에서 정한 암호화 키 길이(7~16바이트)가 16보다 짧으면 LTK의 위쪽을 0으로 가린다. 링크 키는 가리기 전 LTK에서 유도한다. 키 길이는 줄일수록 무차별 대입에 약해지므로, 제품은 16바이트를 요구하도록 설정하는 것이 좋다(이 책 13장의 클래식 키 길이와 함께).
이어폰이 LE에서 숫자 비교로 페어링하고 CTKD로 클래식 링크 키를 만들었다. 공격자가 클래식 쪽 연결만 엿들었다면, 클래식 링크 키의 안전성은 무엇에 달려 있을까?
링크 키는 어디에서 유도했나?
h6·h7: [Vol 3] Part H §2.2.10·§2.2.11 · LTK → 링크 키: §2.4.2.4 · 링크 키 → LTK: §2.4.2.5 · CTKD 개요: §2.3.5.7 · 샘플: Appendix D.6, D.8~D.12
핵심 정리
- SC 2단계 = P-256 공개 키 교환(받으면 곡선 검사) → 인증 1단계(f4 약속 + g2 숫자 / 패스키 20라운드 / OOB) → 인증 2단계(f5로 MacKey‖LTK, f6 확인값).
- f4 = CMACX(U‖V‖Z), g2 = CMACX(U‖V‖Y) mod 2³²(화면은 mod 10⁶), f5는 SALT로 T를 만든 뒤 카운터 0·1로 두 키, f6은 IOcap와 주소까지 묶는다.
- 디버그 키는 개인 키가 공개되어 있어 한쪽만 써도 LTK가 드러난다. 양산 기기에서 꺼 두고, 받으면 거부할 수 있다.
- 레거시 c1·s1은 TK만 알면 다시 계산된다. 방어는 SC Only·보안 모드 1 레벨 4.
- CTKD: CT2 = 1이면 h7, 아니면 h6로 중간 키를 거쳐 LTK ↔ 링크 키. 유도한 키는 원래 키의 보안 속성을 물려받는다.
확인 퀴즈
f5 출력 256비트 중 LTK는 어느 쪽인가?
패스키 방식에서 f4의 Z는?
받은 공개 키가 곡선 위에 있지 않으면?
f6에 IOcap를 넣는 이유는?