song.3_3
하계 보안 세미나 3일차 - ML-KEM·ML-DSA(Module-LWE에서 크기·속도·하이브리드 PQC까지) 본문
PQC 전환은 단순히 알고리즘 하나 바꾸는 일이 아니다
이번 3일차에서는 2일차에서 배웠던 격자 기반 암호가 실제 표준 알고리즘인 ML-KEM과 ML-DSA로 어떻게 이어지는지 배웠다.
2일차가 SIS, LWE, Module-LWE 같은 수학적인 배경을 잡는 시간이었다면, 3일차는 그 개념이 실제 통신, 코드, 패킷 안에서 어떻게 보이는지를 확인하는 느낌이었다.
처음에는 ML-KEM, ML-DSA, HKDF, AES-GCM, Wireshark 같은 단어가 한꺼번에 나와서 헷갈렸는데, 전체 흐름을 잡아보니 결국 중요한 질문은 하나였다.
패킷에 보여도 되는 값은 무엇이고,
절대 보이면 안 되는 값은 무엇인가?
이번 강의에서는 이 기준을 중심으로 PQC가 실제 통신에 들어갈 때 어떤 역할을 하는지 정리할 수 있었다.
안전한 통신에는 비밀과 신원이 둘 다 필요하다
보안통신에서 중요한 것은 단순히 내용을 못 보게 하는 것만이 아니다.
도청을 막는 것도 중요하지만, 내가 통신하고 있는 상대가 진짜 서버인지 확인하는 것도 중요하다.
강의에서는 이걸 비밀과 신원으로 나누어 설명했다.
키 교환 = 비밀을 만드는 역할
서명 = 상대의 신원을 증명하는 역할
예를 들어 클라이언트와 서버가 같은 대칭키를 만들어야 통신 내용을 암호화할 수 있다. 이 역할을 하는 것이 KEM이고, PQC에서는 ML-KEM이 여기에 해당한다.
반대로 “이 서버가 진짜 서버인지”를 확인하려면 전자서명이 필요하다. 인증서에 들어 있는 공개키가 정말 해당 서버의 것인지 확인해야 하기 때문이다. 이 역할을 하는 것이 ML-DSA다.
즉, 양자내성암호로 넘어갈 때는 키 교환만 바꾸면 끝나는 것이 아니라, 서명 쪽도 같이 봐야 한다.
키 교환 → ML-KEM
서명 / 인증서 → ML-DSA
공개키만으로는 진짜 주인을 알 수 없다
강의에서 인증서 이야기도 나왔다. 처음에는 공개키만 있으면 되는 것 아닌가 싶었는데, 공개키 자체에는 “이 키가 누구 것인지”라는 정보가 보장되어 있지 않다.
누군가가 “이게 내 공개키야”라고 말한다고 해서, 그 사람이 진짜 서버인지 알 수는 없다. 공격자가 중간에서 자기 공개키를 보내도 사용자는 겉으로 보기에는 구분하기 어렵다. 이것이 중간자 공격 상황이다.
그래서 인증서가 필요하다.
인증서는 쉽게 말하면 공개키에 신원을 묶어 놓은 디지털 신분증이다.
인증서에는 서버의 도메인, 서버 공개키, 발급자, 유효기간, 그리고 CA의 전자서명이 들어간다.
중요한 점은 개인키는 인증서에 들어가지 않는다는 것이다.
인증서에 들어가는 것은 공개키와 신원정보이고, 개인키는 서버가 따로 비밀로 보관해야 한다.
인증서에 들어가는 것:
서버 신원
서버 공개키
CA의 서명
인증서에 들어가면 안 되는 것:
서버 개인키
결국 인증서는 “이 공개키가 진짜 이 서버의 공개키다”라는 사실을 CA의 서명으로 보장하는 구조다.
암호화, KEM, DSA는 서로 다르다
강의에서 헷갈리기 쉬운 개념으로 공개키 암호화, KEM, DSA가 나왔다. 셋 다 공개키와 비밀키가 나오지만 목표가 다르다.
공개키 암호화는 메시지 자체를 보호하는 방식이다.
상대방의 공개키로 메시지를 암호화하고, 상대방은 자신의 비밀키로 복호화한다.
KEM은 메시지를 직접 암호화하는 것이 아니라, 양쪽이 같은 shared secret을 만들기 위한 방식이다. 여기서 만들어진 shared secret은 이후 대칭키를 만드는 재료가 된다.
DSA는 암호화가 아니라 서명이다.
비밀키로 메시지에 서명하고, 검증자는 공개키로 그 서명이 맞는지 확인한다. 그래서 DSA의 목표는 내용 숨기기가 아니라 출처와 무결성 확인이다.
정리하면 이렇게 볼 수 있다.
공개키 암호화 = 메시지를 잠근다
KEM = shared secret을 합의한다
DSA = 누가 보냈는지 증명한다
이 구분이 잡히니까 ML-KEM과 ML-DSA의 역할도 훨씬 명확해졌다.
ML-KEM은 shared secret을 만드는 방식이다
ML-KEM은 Key Encapsulation Mechanism이다.
긴 데이터를 직접 암호화하는 알고리즘이 아니라, 클라이언트와 서버가 같은 shared secret을 만들도록 도와주는 알고리즘이다.
강의에서는 ML-KEM의 흐름을 KeyGen, Encaps, Decaps 세 단계로 설명했다.
KeyGen → 공개키 pk와 비밀키 sk 생성
Encaps → pk로 ciphertext ct와 shared secret 생성
Decaps → sk와 ct로 같은 shared secret 복원
여기서 패킷에 보여도 되는 값은 pk와 ct다.
반대로 sk와 shared secret은 절대 네트워크에 나오면 안 된다.
이 부분이 가장 중요했다.
보여도 되는 값:
public key(pk)
ciphertext(ct)
숨겨야 하는 값:
secret key(sk)
shared secret(ss)
AES-GCM key
ML-KEM에서 ciphertext는 일반적인 의미의 “암호화된 메시지”라기보다는, shared secret을 복원하기 위한 캡슐에 가깝다.
강의에서도 ct는 shared secret을 담은 상자가 아니라, 비밀키를 가진 쪽이 임시 비밀값을 복원할 수 있게 해주는 재료라고 설명했다. 이 임시 비밀값에서 다시 shared secret을 만들고, 그 shared secret을 HKDF에 넣어 AES-GCM 키를 만든다.
즉 실제 데이터 암호화 흐름은 이렇게 이어진다.
ML-KEM으로 shared secret 생성
→ HKDF로 AES-GCM 키 파생
→ AES-GCM으로 실제 데이터 암호화
shared secret은 바로 쓰지 않는다
ML-KEM으로 얻은 shared secret은 32바이트 값이다.
그런데 이 값을 그대로 데이터 암호화 키로 쓰는 것이 아니라, HKDF 같은 KDF를 거쳐 세션키를 만든다.
여기서 HKDF는 shared secret을 실제 암호화에 쓰기 좋은 키로 다듬어 주는 역할을 한다. 그리고 transcript 같은 통신 문맥 정보를 salt나 info로 같이 넣어 키를 파생한다.
최종적으로 실제 데이터를 보호하는 것은 AES-GCM이다.
shared secret
→ HKDF
→ AES-GCM key
→ nonce + ciphertext + tag
여기서도 역할 구분이 중요하다.
PQC가 실제 데이터를 직접 암호화하는 것이 아니라, 안전한 대칭키를 만들기 위한 앞단 역할을 한다. 실제 본문 암호화는 여전히 AES-GCM 같은 대칭키 암호가 맡는다.
ML-DSA는 암호화가 아니라 서명이다
ML-DSA는 디지털 서명 알고리즘이다.
ML-KEM이 shared secret을 만드는 역할이라면, ML-DSA는 “누가 보냈는지”와 “중간에 바뀌지 않았는지”를 확인하는 역할을 한다.
서버는 secret key로 메시지나 transcript에 서명한다.
클라이언트는 public key로 그 서명이 맞는지 검증한다.
여기서 신기했던 점은 검증자는 비밀키를 몰라도 된다는 것이다.
비밀키는 서명을 만들 때만 필요하고, 검증은 공개키로 가능하다.
Sign:
secret key로 signature 생성
Verify:
public key로 message와 signature 확인
메시지가 1바이트라도 바뀌면 검증이 실패한다.
그래서 서명은 출처 증명과 무결성 확인을 동시에 해준다.
NIST 표준 기준
이번 강의에서는 FIPS 203, 204, 205도 정리했다.
FIPS 203 → ML-KEM
FIPS 204 → ML-DSA
FIPS 205 → SLH-DSA
ML-KEM은 키 합의와 shared secret 생성 쪽 표준이고, ML-DSA는 전자서명 표준이다. SLH-DSA는 해시 기반 전자서명으로, 보수적인 백업 선택지에 가깝다.
SLH-DSA는 해시 기반이라 신뢰는 크지만, 서명 크기가 크고 느리다는 단점이 있다. 그래서 오늘 강의의 중심은 ML-KEM과 ML-DSA였다.
ML-KEM과 ML-DSA는 크기가 커진다
PQC로 전환하면 보안성만 좋아지는 것이 아니라, 운영 비용도 같이 봐야 한다. 특히 패킷 크기와 서명 크기가 커진다.
ML-KEM-768 기준으로 보면 공개키는 1184B, ciphertext는 1088B 정도다. shared secret은 세 파라미터 모두 32B로 동일하다.
ML-KEM-768
public key: 1184B
ciphertext: 1088B
shared secret: 32B
ML-DSA도 마찬가지로 서명 크기가 커진다.
ECDSA-P256 서명은 약 72B 정도인데, ML-DSA-65의 signature는 3309B 정도다.
ECDSA-P256 signature: 약 72B
ML-DSA-65 signature: 약 3309B
이 부분에서 PQC 전환은 단순히 “더 안전한 알고리즘으로 교체”가 아니라는 생각이 들었다.
인증서 체인, 펌웨어, 코드서명, 저장공간, 네트워크 지연까지 같이 고려해야 한다.
TLS 핸드셰이크에서 KEM과 서명이 만나는 위치
강의에서는 TLS 핸드셰이크 안에서 ML-KEM과 ML-DSA가 어디에 들어가는지도 설명했다.
흐름은 대략 이렇다.
ClientHello
→ ML-KEM public key 전송
ServerHello
→ ML-KEM ciphertext 회신
Certificate / CertificateVerify
→ ML-DSA 서명으로 서버 신원 증명
Application Data
→ shared secret에서 파생한 AES-GCM 키로 본문 암호화
즉 KEM은 세션키 합의를 담당하고, 서명은 서버 신원을 증명한다.
둘은 비슷해 보이지만 완전히 다른 역할을 한다.
KEM = 세션키 합의
서명 = 서버 신원 증명
실습에서는 무엇이 보이고 무엇이 숨는지를 확인한다
이번 강의의 실습은 크게 세 단계로 볼 수 있었다.
첫 번째는 로컬에서 ML-KEM, ML-DSA, AES-GCM 출력이 정상인지 확인하는 것이다.
예를 들어 ML-KEM에서는 shared secret이 양쪽에서 같은지 확인하고, ML-DSA에서는 원본 메시지 검증은 True, 변조된 메시지 검증은 False가 나오는지 확인한다.
shared secret equal: True
verify original: True
verify tampered: False
두 번째는 서버와 클라이언트를 나눠 실행하는 것이다.
작은 TLS처럼 client_hello, server_hello, encrypted_request, encrypted_response 흐름을 직접 만들어 본다.
세 번째는 Wireshark로 패킷을 보는 것이다.
여기서 가장 중요한 건 “패킷에 보여도 되는 값”과 “보이면 안 되는 값”을 구분하는 것이다.
패킷에 보이는 값은 다음과 같다.
kem_public_key_b64
kem_ciphertext_b64
signature_b64
nonce_b64
ciphertext_tag_b64
반대로 보이면 안 되는 값은 다음과 같다.
shared secret
AES-GCM key
plaintext response body
이 구분이 실제 보안통신을 이해하는 데 가장 중요한 부분이라고 느꼈다.
하이브리드 전환
전환기에는 기존 ECDH를 바로 버리고 ML-KEM만 쓰는 것이 아니라, X25519와 ML-KEM을 함께 사용하는 하이브리드 방식도 나온다.
예를 들어 X25519MLKEM768은 기존 X25519와 ML-KEM-768을 함께 사용하는 형태다.
이 방식은 기존 방식의 안정성과 PQC의 양자내성 보안을 같이 가져가려는 전환기 전략이라고 볼 수 있다.
다만 하이브리드 방식은 key_share 크기가 커진다.
ClientHello가 커지면 MTU, 지연, 중간장비 호환성 같은 문제도 같이 봐야 한다.
그래서 PQC 전환은 “지원한다 / 지원하지 않는다”만 보면 안 된다.
실제로 어떤 그룹이 협상되었는지, 패킷 크기가 얼마나 커졌는지, 중간장비가 막지는 않는지까지 확인해야 한다.
구현이 새면 수학이 맞아도 깨질 수 있다
마지막으로 구현 취약점 이야기도 중요했다.
수학적으로 안전한 알고리즘이라도 구현에서 정보가 새면 공격이 가능해질 수 있다.
특히 PQC 구현에서는 디캡슐화 실패 처리, 상수시간 구현, 랜덤 품질, 패킹/역패킹 버그 같은 부분이 중요하다.
예를 들어 실패 여부가 시간 차이나 오류 메시지로 드러나면 공격자가 그 차이를 이용할 수 있다.
또 비밀값에 따라 분기나 배열 접근, 루프 횟수가 달라지면 타이밍 정보가 새어 나갈 수 있다.
강의에서는 KyberSlash 사례도 언급했다. ML-KEM/Kyber 구현에서 비밀 의존 나눗셈 타이밍 때문에 키 복원 가능성이 제기되었고, 여러 구현이 패치되었다. 이걸 보면서 “표준 알고리즘을 쓴다”는 것만으로는 부족하고, 구현 방식까지 안전해야 한다는 점을 다시 느꼈다.
마무리
이번 3강은 2강에서 배운 Module-LWE 개념이 실제 표준과 통신 흐름으로 이어지는 내용이었다.
정리하면 이렇게 볼 수 있다.
ML-KEM은 shared secret을 만드는 역할
ML-DSA는 서버 신원과 메시지 무결성을 증명하는 역할
shared secret은 HKDF를 거쳐 AES-GCM 키가 됨
실제 데이터 보호는 AES-GCM이 담당
패킷에는 pk, ct, signature는 보일 수 있음
shared secret, AES key, plaintext는 보이면 안 됨
가장 기억에 남은 점은 PQC 전환이 단순히 알고리즘 하나 바꾸는 일이 아니라는 것이었다.
키 교환, 서명, 인증서, 패킷 크기, 중간장비, 구현 취약점까지 같이 봐야 실제로 안전한 전환이 가능하다.
이번 강의를 듣고 나니 ML-KEM과 ML-DSA가 그냥 어려운 이름의 알고리즘이 아니라, TLS 같은 실제 보안통신 안에서 각각 “비밀 만들기”와 “신원 증명”을 맡는 부품이라는 점이 조금 더 명확해졌다.
'하계 보안 세미나' 카테고리의 다른 글
| 하계 보안 세미나 6일차 - 보안적합성 검사 (0) | 2026.07.10 |
|---|---|
| 하계 보안 세미나 5일차 - 시큐어코딩 (임베디드·자동차 코딩 표준) (0) | 2026.07.10 |
| 하계 보안 세미나 4일차 - 자동차 보안 이해 (0) | 2026.07.06 |
| 하계 보안 세미나 2일차 - 격자 기반 암호 (SIS · LWE부터 Kyber와 ML-KEM) (0) | 2026.07.06 |
| 하계 보안 세미나 1회차 - 깨지는 암호의 해부학 (0) | 2026.07.06 |