안동민 개발노트

본문 시작

암호화의 기초

대칭키·공개키·키 교환·해시·MAC·디지털 서명의 서로 다른 역할과 TLS에서의 조합을 이해합니다.

HTTP는 메시지를 평문으로 보냅니다.

전송 경로에서 평문 트래픽을 관찰할 수 있는 주체는 요청 경로, 쿠키, 본문에 담긴 민감 정보를 읽을 수 있고, 중간자는 응답을 바꿔치기할 수도 있습니다.

HTTPS는 이 문제를 줄이기 위해 HTTP를 TLS(Transport Layer Security) 위에 올립니다.

TLS로 내용을 보호해도 IP 주소·포트·통신 시각·트래픽 크기 같은 연결 흔적은 남습니다.

TLS를 이해하려면 “암호화”를 하나의 기능으로 뭉뚱그리면 안 됩니다.

실제 보안 연결은 대칭키 암호, 공개키 기반 인증과 키 교환, 해시, MAC, 디지털 서명을 서로 다른 역할로 조합합니다.


대칭키 암호화

대칭키 암호화(Symmetric Encryption)는 암호화와 복호화에 같은 비밀 키를 사용하는 방식입니다.

속도가 빠르기 때문에 TLS에서 실제 애플리케이션 데이터를 보호하는 데 쓰입니다.

대칭키 암호화 동작
암호화:  평문 + 비밀 키 + nonce  → 암호문
복호화:  암호문 + 같은 키 + nonce → 평문

핵심: 양쪽이 같은 비밀 키를 이미 알고 있어야 한다
  • AES-GCM: 128/256비트; TLS에서 널리 쓰이는 AEAD 방식.
  • ChaCha20-Poly1305: 256비트; 소프트웨어 구현에서 성능이 좋은 AEAD.
  • AES-CBC + HMAC: 128/256비트; 과거 TLS 1.2에서 사용, 구성 주의 필요.
  • DES: 56비트; 안전하지 않아 사용하면 안 됨.
  • 3DES: 112비트 수준; 신규 TLS 구성에서는 사용하지 않음.

대칭키 암호의 핵심 문제는 “키를 어떻게 안전하게 공유할 것인가”입니다.

네트워크에 비밀 키를 그대로 보내면 중간자가 그 키를 보고 이후 통신을 모두 읽을 수 있습니다.

그래서 TLS는 핸드셰이크에서 키 교환을 먼저 수행하고, 그 결과로 만들어진 트래픽 키를 대칭키 암호에 사용합니다.


공개키 암호와 키 교환

공개키 암호 방식은 공개키와 개인키라는 서로 다른 키를 사용합니다.

공개키는 배포할 수 있지만, 개인키는 소유자만 보관해야 합니다.

다만 현대 TLS에서 공개키 기술의 핵심 용도는 “대량 데이터를 공개키로 암호화”하는 것이 아니라 서버 인증, 서명, 키 교환입니다.

  • RSA-PSS: 디지털 서명; 인증서 체인이나 핸드셰이크 서명에 사용.
  • ECDSA: 디지털 서명; 작은 키로 효율적인 서명/검증.
  • Ed25519: 디지털 서명; SSH 등에서 널리 쓰이며 TLS에서도 지원 가능.
  • ECDHE: 임시 키 교환; 전방 비밀성을 제공하는 TLS 핵심 방식.
  • RSA key transport: 레거시 키 운반 방식; TLS 1.3에서는 제거, TLS 1.2에서도 비권장.

공개키 암호를 이해할 때 가장 흔한 오해는 “공개키로 세션 키를 암호화해서 보내면 TLS가 끝난다”는 설명입니다.

과거 TLS 1.2에는 RSA key transport가 있었지만, 현대 TLS는 ECDHE 같은 임시 키 교환으로 공유 비밀을 만들고, 인증서는 그 키 교환이 진짜 서버와 이루어졌는지 확인하는 데 사용합니다.


TLS의 하이브리드 구조

TLS는 하나의 암호 기법만 쓰지 않습니다.

인증서 기반 TLS 연결에서는 공개키 인증과 임시 키 교환으로 공유 비밀을 만들고, 파생한 대칭키로 레코드를 보호합니다. TLS 1.3은 ServerHello 이후의 핸드셰이크 메시지도 암호화합니다. PSK 기반 연결은 인증서 대신 미리 공유한 비밀을 사용할 수 있습니다.

이 구조를 하이브리드 암호화라고 부를 수 있습니다.

공개키 기술은 신원 확인과 키 합의에 강하고, 대칭키 암호는 대량 데이터 보호에 빠릅니다.


해시 함수와 MAC

해시 함수(Hash Function)는 임의 길이 데이터를 고정 길이의 값으로 변환합니다.

단, 해시는 “고유한 값”이 아닙니다.

출력 길이가 고정되어 있으므로 이론적으로 충돌은 존재합니다.

좋은 암호학적 해시는 충돌을 찾기 어렵고, 입력이 조금만 바뀌어도 출력이 크게 달라지며, 출력만 보고 입력을 역산하기 어렵도록 설계됩니다.

  • MD5: 128비트; 충돌 공격 때문에 보안 용도로 사용 금지.
  • SHA-1: 160비트; 충돌 공격 때문에 사용 중단 방향.
  • SHA-256: 256비트; 널리 쓰이는 SHA-2 계열 해시.
  • SHA-384: 384비트; TLS cipher suite에서도 사용.
  • SHA-512: 512비트; SHA-2 계열의 더 긴 출력.
  • SHA-3: 다양; SHA-2와 다른 구조의 표준 해시.

해시만으로는 “누가 만든 값인지”를 증명하지 못합니다.

그래서 메시지 무결성과 인증이 필요할 때는 비밀 키를 함께 쓰는 HMAC 같은 MAC(Message Authentication Code)을 사용합니다.

crypto_basics.py
import hashlib
import hmac
import secrets

def hash_demo():
    """SHA-256 해시 계산"""
    message = "Hello, TLS!"
    hash_value = hashlib.sha256(message.encode()).hexdigest()
    print(f"메시지: {message}")
    print(f"SHA-256: {hash_value}")

    message2 = "Hello, TLS?"
    hash_value2 = hashlib.sha256(message2.encode()).hexdigest()
    print(f"메시지 변경 후 SHA-256: {hash_value2}")

def hmac_demo():
    """HMAC으로 메시지 무결성과 공유 비밀 소유를 함께 확인"""
    key = secrets.token_bytes(32)
    message = b"transfer: 1000 to account 1234"

    mac = hmac.new(key, message, hashlib.sha256).digest()
    print(hmac.compare_digest(mac, hmac.new(key, message, hashlib.sha256).digest()))

    tampered = b"transfer: 9999 to account 5678"
    print(hmac.compare_digest(mac, hmac.new(key, tampered, hashlib.sha256).digest()))

hash_demo()
hmac_demo()

디지털 서명의 원리

디지털 서명(Digital Signature)은 개인키로 서명하고 공개키로 검증하는 기술입니다.

“해시값을 개인키로 암호화한다”는 설명은 RSA 일부 형태를 지나치게 단순화한 표현입니다.

더 정확히는 서명 알고리즘이 메시지 또는 메시지 해시와 개인키를 입력으로 받아 서명값을 만들고, 검증자는 공개키로 그 서명이 해당 메시지에 대해 유효한지 확인합니다.

TLS 인증서에서는 이 메커니즘이 핵심적으로 쓰입니다.

CA가 인증서 내용에 서명하고, 브라우저는 신뢰 저장소의 CA 공개키로 인증서 체인을 검증합니다.

인증서 기반 TLS 1.3이나 ECDHE를 쓰는 TLS 1.2에서는 서버가 핸드셰이크 서명으로 해당 개인키의 소유를 증명합니다. 서명으로 사람이나 조직의 신원을 해석하려면 인증서 정책과 키 관리에 대한 신뢰도 필요합니다.

키와 결과로 구분하는 암호 기능

키와 결과로 구분하는 암호 기능

키와 결과로 구분하는 암호 기능
기능필요한 키와 결과검증으로 알 수 있는 범위
해시키 없이 데이터를 요약한 해시값같은 입력의 요약을 비교합니다. 공격자도 다시 계산할 수 있어 발신자를 인증하지 못합니다.
HMAC공유 비밀 키로 만든 인증 태그공유 키를 가진 측이 만든 메시지인지 검증합니다. 같은 키 소유자끼리 작성자를 구별하지는 못합니다.
디지털 서명개인키로 서명, 공개키로 검증해당 키의 서명과 메시지의 일치를 검증합니다. 신원 해석은 공개키를 누구와 연결해 신뢰하는지에 달렸습니다.
AEAD대칭키·nonce로 만든 암호문과 태그내용을 숨기고 암호문과 부가 데이터의 무결성을 검사합니다. nonce 사용 규칙은 선택한 알고리즘을 따라야 합니다.
기능: 해시
필요한 키와 결과: 키 없이 데이터를 요약한 해시값
검증으로 알 수 있는 범위: 같은 입력의 요약을 비교합니다. 공격자도 다시 계산할 수 있어 발신자를 인증하지 못합니다.
기능: HMAC
필요한 키와 결과: 공유 비밀 키로 만든 인증 태그
검증으로 알 수 있는 범위: 공유 키를 가진 측이 만든 메시지인지 검증합니다. 같은 키 소유자끼리 작성자를 구별하지는 못합니다.
기능: 디지털 서명
필요한 키와 결과: 개인키로 서명, 공개키로 검증
검증으로 알 수 있는 범위: 해당 키의 서명과 메시지의 일치를 검증합니다. 신원 해석은 공개키를 누구와 연결해 신뢰하는지에 달렸습니다.
기능: AEAD
필요한 키와 결과: 대칭키·nonce로 만든 암호문과 태그
검증으로 알 수 있는 범위: 내용을 숨기고 암호문과 부가 데이터의 무결성을 검사합니다. nonce 사용 규칙은 선택한 알고리즘을 따라야 합니다.

면접 포인트

  • 대칭키 vs 공개키?: 대칭키는 같은 비밀 키로 빠르게 데이터 보호, 공개키는 인증·서명·키 교환에 적합.
  • TLS에서 둘 다 쓰는 이유?: 키 합의·인증과 대칭키 AEAD의 레코드 보호를 조합; TLS 1.3은 핸드셰이크도 암호화.
  • 해시와 HMAC 차이?: 해시는 공개 계산 가능, HMAC은 비밀 키를 알아야 같은 값을 만들 수 있음.
  • 디지털 서명 원리?: 개인키로 서명하고 공개키로 검증; 출처·부인 방지 해석에는 신원 확인과 키 관리가 필요.

다음 절에서는 이 암호화 기법들이 실제로 어떻게 조합되어 TLS 핸드셰이크를 이루는지 살펴보겠습니다.