암호학 실무에서 자주 무너지는 지점은 알고리즘 자체보다 난수, 키 관리, 운영 모드, 오류 처리, 인증 검증을 조합하는 설계다. 이 글은 보안 진단자와 리버서 관점에서 암호 구현을 볼 때 무엇을 의심하고 확인해야 하는지 정리한다.

대상: 보안 운영자, 진단자, 리버서
관점: 구현 실수와 설계 실패
버전: 복원/확장 병합본 2026

관련 영상

문서 흐름

    1. 암호학은 수학보다 설계다
    1. 난수와 엔트로피
    1. 무결성, 인증, 비밀번호 저장
    1. 키 관리와 KDF
    1. CBC / CTR / GCM 운영 모드
    1. RSA, PKCS#1 v1.5, OAEP
    1. 암호학적 리버싱
    1. 취약점 분석 패턴
    1. 양자 내성 전환
    1. 감사 체크리스트

0. 들어가며: 암호학은 왜 “수학”이 아니라 “설계”인가?

많은 보안 전문가가 암호학을 복잡한 수학 공식의 집합으로 생각하고 멀리합니다. 하지만 실무 보안에서 더 자주 무너지는 지점은 알고리즘의 수학적 안전성이 아니라 알고리즘을 조립하고 운영하는 방식입니다.

강한 알고리즘을 썼다는 말은 출발점일 뿐입니다. 실무 질문은 “무슨 알고리즘인가?”가 아니라 “어떤 키로, 어떤 모드로, 어떤 난수로, 어떤 오류 처리와 인증 검증을 붙여 사용했는가?”입니다.

따라서 이 문서는 수학 증명보다는 보안 진단자가 실제 코드, 바이너리, 프로토콜, 운영 환경을 볼 때 무엇을 의심해야 하는지에 초점을 둡니다.

1. 난수와 엔트로피: 예측 가능성의 위험성

암호화의 핵심은 예측 불가능성입니다. 키, IV, Nonce, Salt, challenge, 세션 토큰처럼 보안 경계를 구성하는 값은 공격자가 미래 값을 예측하거나 과거 값을 재구성할 수 없어야 합니다.

분석 사례: 범위가 좁은 시드

특정 모듈이 세션키를 만들 때 gettimeofday().tv_usec 값을 시드로 사용한다고 가정해봅시다. 마이크로초 값은 0부터 999,999까지라 경우의 수가 최대 1,000,000개에 불과합니다. 공격자가 요청 시각을 대략 알고 있다면 실제 탐색 공간은 훨씬 더 좁아집니다.

위험한 패턴

  • rand(), rand_r(), Math.random() 계열로 키 생성
  • 시간, PID, 카운터, 사용자 ID를 시드로 사용
  • 난수값을 로그나 디버그 화면에 출력
  • 테스트용 고정 시드를 운영에 그대로 사용

안전한 원칙

  • 운영체제 또는 검증된 라이브러리의 CSPRNG 사용
  • 키와 Nonce 생성 책임을 애플리케이션 임의 로직에 두지 않기
  • 분산 시스템에서는 충돌 가능성을 설계 단계에서 제거
  • 장기 비밀값과 일회성 난수값의 용도를 분리

전문가의 눈: CSPRNG

암호키, IV, Nonce, Salt 등은 반드시 OS 수준 CSPRNG 또는 검증된 암호 라이브러리 API로 생성해야 합니다. 핵심은 단순히 “랜덤해 보이는 값”이 아니라 공격자가 내부 상태를 모르는 상황에서 다음 출력을 예측할 수 없는 값입니다.

2. 무결성, 진정성, 비밀번호 저장

무결성(Integrity)과 진정성(Authenticity)은 다르다

일반 해시 → 무결성

SHA-256 같은 해시는 데이터가 바뀌었는지 확인하는 지문 역할을 합니다. 하지만 누구나 다시 계산할 수 있으므로 공격자가 데이터를 바꾸고 해시도 함께 바꾸면 검증이 무력화됩니다.

MAC / AEAD 태그 → 진정성

HMAC이나 AEAD 인증 태그는 비밀키를 아는 주체만 만들 수 있습니다. 따라서 메시지가 바뀌지 않았는지뿐 아니라, 권한 있는 주체가 만든 메시지인지까지 확인할 수 있습니다.

실무 실수: “암호문 + SHA-256”

암호문 옆에 단순 SHA-256 해시를 붙이는 것은 인증이 아닙니다. 공격자도 암호문을 변조한 뒤 해시를 다시 계산할 수 있기 때문입니다. 인증을 원한다면 HMAC 또는 AEAD를 사용해야 합니다.

비밀번호는 암호화하지 말고 해시해야 한다

비밀번호는 시스템이 평문을 다시 알아야 하는 데이터가 아닙니다. 따라서 AES 같은 대칭키 암호로 “복호화 가능한 형태”로 저장하는 것은 원칙적으로 부적절합니다.

  • 비밀번호 저장에는 Argon2id, bcrypt, scrypt, PBKDF2 같은 전용 Password Hashing 알고리즘을 사용합니다.
  • 사용자별 Salt를 적용해 같은 비밀번호라도 다른 저장값이 나오게 해야 합니다.
  • 오프라인 대입 공격을 늦추기 위해 충분한 비용 파라미터를 설정해야 합니다.
  • 단순 SHA-256, MD5, Base64, “자체 암호화”는 비밀번호 저장 방식이 아닙니다.

3. 키 관리: 암호의 강도는 키 운영에서 결정된다

암호 알고리즘이 강해도 키가 잘못 생성·저장·공유·회전되면 전체 시스템은 쉽게 무너집니다. 실무 감사에서 가장 먼저 봐야 할 것은 “어떤 알고리즘을 썼는가”가 아니라 키가 어디서 와서 어디로 가는가입니다.

KDF와 Key Separation

하나의 마스터 비밀값에서 여러 용도의 키가 필요할 때 단순히 문자열을 자르거나 해시를 한 번 수행하는 방식은 위험합니다. 이런 경우에는 HKDF 같은 KDF를 사용해 용도별 키를 분리해야 합니다.

왜 HKDF를 쓰나요? 주스 착즙 비유

  • Extract: 원본 비밀값, 예를 들어 키 교환 결과에 섞여 있을지도 모를 편향과 불순물을 걸러내고 암호학적으로 다루기 좋은 의사난수 키를 추출합니다.
  • Expand: 목적 문자열(info/context)을 넣어 암호화용 키, MAC용 키, 세션별 키, 송신 방향 키, 수신 방향 키처럼 서로 다른 컵에 나누어 담습니다.

이렇게 하면 Key Separation이 달성됩니다. 하나의 키를 암호화와 인증, 송신과 수신, 파일 암호화와 토큰 서명에 동시에 쓰면 알고리즘 사이의 상호작용이나 키 노출 범위가 커질 수 있습니다. HKDF는 같은 뿌리에서 나온 비밀값을 서로 독립적인 용도별 키로 분리해, 한 영역의 문제가 다른 영역으로 번지는 위험을 낮춥니다.

키 저장과 운영

저장 위치

소스코드, Git 히스토리, Docker 이미지, 평문 설정 파일, 로그에 키가 남아 있지 않은지 확인합니다. 환경 변수도 /proc/self/environ, 디버그 덤프, 런타임 진단 도구를 통해 노출될 수 있으므로 운영 비밀값은 가능하면 KMS, HSM, Secret Manager로 분리합니다.

접근 권한

KMS, HSM, Secret Manager 등 전용 시스템을 사용하고 최소 권한 원칙을 적용합니다.

수명 주기

키 회전, 폐기, 사고 시 재발급, 과거 데이터 재암호화 정책이 존재하는지 확인합니다.

4. 운영 모드의 이해와 취약점: CBC / CTR / GCM

CBC 모드와 IV

CBC에서 IV는 비밀값일 필요가 없습니다. 일반적으로 암호문과 함께 전송될 수 있습니다. 중요한 것은 암호화 시점에 IV가 예측 불가능해야 하며, IV가 무결성 보호 범위에 포함되어야 한다는 점입니다.

IV가 변조되면 첫 번째 평문 블록이 공격자가 의도한 방식으로 바뀔 수 있습니다. 따라서 CBC를 쓴다면 “암호화만”으로는 부족하고 반드시 MAC 또는 AEAD 수준의 인증이 붙어야 합니다.

P_1 = D_k(C_1) XOR IV
P_n = D_k(C_n) XOR C_{n-1}

분석가 관점에서는 대칭키를 확보했지만 IV를 모르는 특수 상황에서도, CBC 구조상 첫 번째 블록을 제외한 나머지 블록은 이전 암호문 블록을 이용해 복호화할 수 있습니다.

CTR 모드와 Nonce

Nonce 재사용은 구조적 재앙

CTR/GCM 계열에서 Nonce는 비밀값이 아닙니다. 핵심은 공격자가 Nonce를 아느냐가 아니라 동일 키에서 Nonce가 재사용되었느냐입니다. 같은 키와 Nonce 조합이 반복되면 같은 키스트림이 생성되고, 두 암호문을 XOR했을 때 평문 간 XOR 관계가 드러납니다.

C1 = P1 XOR Stream(K, Nonce)
C2 = P2 XOR Stream(K, Nonce)
C1 XOR C2 = P1 XOR P2

AES-GCM과 AES-GCM-SIV

AES-GCM

현대 프로토콜에서 널리 쓰이는 고성능 AEAD입니다. 기밀성과 인증을 함께 제공하지만, Nonce 재사용에 매우 민감합니다.

AES-GCM-SIV

Nonce가 실수로 재사용되어도 일반 GCM처럼 즉시 파국으로 이어지지 않도록 설계된 misuse-resistant AEAD입니다. 다만 Nonce 재사용을 권장한다는 뜻은 아닙니다.

AEAD의 절대 원칙

태그 검증에 실패한 평문은 존재하지 않는 것으로 취급해야 합니다. 라이브러리가 내부 버퍼에 일부 평문을 생성했더라도 애플리케이션은 이를 절대 사용해서는 안 됩니다.

5. RSA 암호화와 PKCS#1 v1.5: “깨진 것”과 “위험한 것”은 다르다

RSA를 볼 때 가장 먼저 구분해야 하는 것은 암호화서명입니다. RSAES는 암호화, RSASSA는 서명입니다. 둘은 같은 RSA 수학 구조를 공유하지만 안전성 조건과 패딩 방식이 다릅니다.

PKCS#1 v1.5 암호화 패딩의 위치

RSAES-PKCS1-v1_5의 패딩 포맷은 대략 다음과 같습니다.

EM = 0x00 || 0x02 || PS || 0x00 || M
  • PS는 0이 아닌 무작위 바이트열입니다.
  • 이 구조 자체가 “새로운 수학적 붕괴”를 맞은 것은 아닙니다.
  • 하지만 chosen-ciphertext 상황에서 복호화 오류 차이, 시간 차이, 로그 차이, 응답 차이가 보이면 padding oracle이 될 수 있습니다.

핵심 판단: PKCS#1 v1.5 자체보다 Oracle 노출 여부가 중요하다

외부 사용자가 임의 암호문을 반복 제출할 수 있고, 서버가 패딩 오류·길이 오류·키 오류·MAC 오류를 서로 다르게 보여주거나 시간 차이를 노출한다면 위험합니다. 이때 공격자는 “복호화 결과를 직접 보지 않고도” 내부 정보를 조금씩 얻을 수 있습니다.

상황판단실무 조치
신규 설계에서 RSA 암호화 필요PKCS#1 v1.5 선택 금지에 가깝게 판단RSA-OAEP 또는 KEM/하이브리드 구조 사용
기존 시스템 호환 때문에 PKCS#1 v1.5 유지Legacy risk복호화 API 노출 최소화, 오류 응답 통합, timing 차이 점검
랜덤 CEK/세션키 래핑 용도상대적으로 제한적 위험RNG, 키 길이, oracle 방어, 실패 처리 확인
사용자 입력 메시지를 직접 RSA로 암호화부적절하이브리드 암호화 구조로 변경

RSA-OAEP와 RSA-PSS

암호화: RSA-OAEP

신규 RSA 암호화에서는 OAEP가 기본 선택입니다. OAEP도 구현과 파라미터 선택이 중요하지만, PKCS#1 v1.5 암호화보다 현대적인 보안 모델에 맞습니다.

서명: RSA-PSS

서명에서는 PKCS#1 v1.5 서명보다 RSA-PSS가 현대 권장 방식입니다. 암호화 패딩 논의와 서명 패딩 논의를 혼동하지 않아야 합니다.

PKCS#1 v1.5 복호화 감사 포인트

  • 복호화 실패 원인이 외부 응답에서 구분되지 않는가?
  • 성공/실패 경로의 처리 시간이 관찰 가능하게 다른가?
  • 패딩 검사, 길이 검사, 구분자 검색이 데이터 의존 분기를 만드는가?
  • 실패 시 랜덤 대체값 또는 implicit rejection 같은 방어가 적용되는가?
  • RSA blinding이 적용되어 개인키 연산의 side-channel 위험을 줄이는가?
  • 복호화 API가 외부에 직접 노출되어 있거나 반복 호출 가능한가?

결론

**“PKCS#1 v1.5 무작위 패딩 로직 자체에 새로운 대형 붕괴가 있느냐?”**라는 질문에는 보통 “그런 의미는 아니다”라고 답할 수 있습니다. 그러나 **“신규 시스템에서 안전한 선택인가?”**라는 질문에는 “아니다. OAEP 또는 KEM 기반 구조로 가야 한다”가 실무적 답입니다.

6. 분석가의 눈: 암호학적 리버싱과 프로토콜 해부

표준 문서는 알고리즘의 수학적 명세를 설명하지만, 실제 구현체의 데이터 흐름은 바이너리 분석과 동적 분석으로 확인해야 합니다. 특히 상용 모듈은 표준 알고리즘 위에 커스텀 래핑, 인코딩, 엔디안 변환, 키 스케줄 캐싱을 덧씌우는 경우가 많습니다.

Step 1. 엔진 식별

S-Box, 라운드 상수, 초기 벡터, 상수 테이블, 함수 호출 패턴을 통해 AES, SEED, ARIA, DES, RSA 등을 식별합니다.

Step 2. 모드 식별

CBC, CTR, GCM, ECB 등 운영 모드를 확인합니다. 같은 블록 암호라도 모드가 다르면 보안 성질이 완전히 달라집니다.

Step 3. 래핑 확인

패딩, 커스텀 Base64, 문자열 치환, 엔디안 처리, 헤더 삽입, MAC 결합 순서를 확인합니다.

마스터 키와 라운드 서브키

리버싱 중 GDB나 Frida로 키처럼 보이는 값이 여러 개 보인다면 Key Schedule 때문일 수 있습니다. 예를 들어 블록 암호는 하나의 마스터 키에서 라운드별 서브키를 생성합니다. 분석 목적상 전체 키 스케줄 배열을 덤프하면 복잡한 키 생성 로직을 끝까지 해석하지 않고도 암·복호화 재현이 가능한 경우가 있습니다.

바이너리 속 암호학 DNA: S-Box, 상수, 회전

암호 알고리즘을 리버싱할 때 마주치는 S-Box, 라운드 상수, 회전 연산은 단순한 구현 잡음이 아니라 알고리즘의 설계 의도를 보여주는 강한 단서입니다. 이 부분은 복구본의 설명을 살려 분석가 관점의 언어로 보강했습니다.

1. S-Box: 비밀 메뉴판과 혼돈(Confusion)

S-Box는 입력과 출력 사이에 비선형 관계를 만드는 치환 테이블입니다. 단순한 덧셈이나 XOR만 반복되는 구조라면 선형식으로 모델링될 수 있지만, S-Box는 입력을 엉뚱한 출력으로 튀게 만들어 수학적 역산 비용을 높입니다.

  • 식별 단서: 256바이트 테이블, 고정 치환표, AES/SEED/ARIA 계열 상수 배열.
  • 분석 의미: 선형·미분 분석을 어렵게 하는 핵심 구성 요소이며, 바이너리에서 알고리즘을 식별하는 지문 역할을 합니다.

비유하자면 선형 관계는 1→2, 2→4처럼 예측 가능한 지도이고, 비선형 관계는 1→9, 2→0처럼 규칙을 일부러 뒤틀어 하나의 공식으로 접히지 않게 만드는 장치입니다.

2. 공개 검증 가능한 상수: Nothing-up-my-sleeve

원주율, 제곱근, 특정 다항식 기반 상수는 난수원이라기보다 설계자가 임의 숫자를 골라 백도어를 숨기지 않았다는 공개 검증성을 제공합니다. “숫자를 어디서 가져왔는가”를 설명할 수 있어야 알고리즘 설계에 대한 신뢰가 생깁니다.

  • 라운드 상수: 반복 구조가 자기 자신과 겹치는 것을 막고 slide attack 같은 구조적 공격을 어렵게 합니다.
  • 로또 추첨 비유: 상수가 당첨 번호라면 공개 검증성은 추첨 생중계입니다. 설계자가 밀실에서 숫자를 정하지 않았다는 증거입니다.

3. 회전 및 비트 연산: 나비 효과와 확산(Diffusion)

회전(rotate), 시프트, XOR, AND, OR 같은 비트 연산은 암호 구현에서 자주 등장합니다. 이들은 CPU가 빠르게 처리할 수 있는 연산이면서, 입력의 작은 변화가 여러 라운드를 거치며 전체 출력으로 퍼지도록 돕습니다.

  • 쇄도 효과: 입력 비트 하나가 바뀌었을 때 출력의 많은 비트가 바뀌어야 합니다.
  • 잉크 한 방울 비유: 맑은 물에 잉크 한 방울을 떨어뜨린 뒤 휘저으면 전체 색이 바뀌듯, 회전과 XOR은 작은 차이를 전체 상태로 확산시키는 교반기 역할을 합니다.
  • 리버싱 단서: 일정한 rotate-left/rotate-right 패턴, 라운드별 상수와 XOR되는 구조, 워드 단위 엔디안 변환이 반복되면 특정 계열의 블록 암호나 해시 함수를 의심할 수 있습니다.

수학적 백도어란? 조작된 자물쇠 비유

일반적인 백도어가 비밀 패스워드를 심는 것이라면, 수학적 백도어는 자물쇠 내부 핀을 미세하게 깎아두는 것에 가깝습니다. 겉보기에는 튼튼해 보이지만 설계자만 아는 특정 관계, 상수, 곡선 파라미터, 난수 생성 구조가 있으면 계산 지름길이 생길 수 있습니다.

따라서 리버싱과 설계 검토에서는 “상수가 무엇인가”뿐 아니라 그 상수가 왜 선택되었는가, 선택 과정이 공개적으로 검증 가능한가, 테스트 벡터와 표준 문서가 일관되는가를 함께 확인해야 합니다.

리버싱 식별 포인트

대상식별 단서주의점
ECB블록 간 연결 없이 같은 입력 블록이 같은 출력 블록으로 반복이미지·정형 데이터 패턴 누출
CBC복호화 결과와 이전 암호문 블록의 XORIV 무결성, padding oracle 확인
CTR증가하는 카운터를 암호화한 뒤 평문과 XORNonce 재사용과 malleability 확인
GCMCTR 흐름 + GHASH/Galois Field 곱셈 루틴Nonce 재사용, 태그 검증 실패 처리 확인
RSA큰 정수 모듈러 지수 연산, DER key parsing, OAEP/v1.5 depadding복호화 oracle, padding check timing 확인

테스트 벡터 검증

알고리즘을 직접 구현하거나 리버싱으로 복원했다면 반드시 표준 테스트 벡터와 비교해야 합니다. S-Box와 라운드 함수가 맞아 보여도 엔디안, 패딩, IV 적용, 인코딩 방식 하나로 결과가 완전히 달라질 수 있습니다.

7. 암호 구현 취약점 분석 패턴

암호 구현의 취약점은 대부분 “약한 알고리즘”이 아니라 경계 조건, 오류 처리, 키 관리, 재사용, 인증 누락에서 발생합니다.

패턴위험분석 질문
Padding OracleCBC/RSA v1.5에서 복호화 정보 누출오류 메시지, HTTP status, timing, 로그가 다른가?
Nonce/IV 재사용CTR/GCM에서 평문 관계 또는 인증키 정보 노출분산 환경에서 충돌 방지가 설계되어 있는가?
Encrypt-then-Hash단순 해시 재계산 가능비밀키 기반 MAC 또는 AEAD 태그인가?
태그 검증 무시변조된 평문 사용검증 실패 예외를 삼키고 계속 처리하지 않는가?
키/시드 로그 노출사후 복호화와 세션 탈취디버그 로그, APM, crash dump에 비밀값이 남는가?
다운그레이드/폴백강한 모드에서 약한 모드로 강제 전환호환성 옵션이 공격자가 선택 가능한가?

실무 진단 문장

“AES-256을 사용하므로 안전하다”는 결론은 불충분합니다. “AES-256-GCM을 사용하며, 키는 CSPRNG/KMS 기반으로 생성·관리되고, Nonce는 동일 키에서 재사용되지 않으며, 태그 검증 실패 시 평문을 폐기한다” 정도까지 확인해야 실무적으로 의미 있는 판단입니다.

8. 미래 위협: 하이브리드 양자 내성 프로토콜

양자 내성 전환은 “RSA를 당장 모두 버린다”는 단순한 이야기가 아닙니다. 더 현실적인 질문은 지금 수집된 암호문이 미래에 복호화될 수 있는가, 그리고 장기 기밀성이 필요한 데이터에 어떤 전환 계획이 있는가입니다.

Harvest Now, Decrypt Later

공격자는 오늘 복호화할 수 없는 트래픽도 저장해둘 수 있습니다. 나중에 충분한 양자 컴퓨팅 능력이나 새로운 공격 기법이 등장하면 과거 트래픽이 위험해질 수 있습니다. 장기 기밀성이 중요한 시스템은 지금부터 하이브리드 키 교환과 양자 내성 KEM 전환을 고려해야 합니다.

ML-KEM

NIST FIPS 203에서 표준화된 모듈 격자 기반 KEM입니다. 기존 ECC/DH 키 교환과 결합한 하이브리드 구조에서 자주 논의됩니다.

PQ3 같은 메시징 프로토콜

단일 알고리즘이 아니라 키 교환, 래칫, 장기 대화 보호, 침해 후 회복성을 함께 다루는 프로토콜 설계 관점으로 봐야 합니다.

9. 보안 점검 체크리스트

암호화 모듈, 프로토콜, 바이너리, 서버 API를 분석할 때 아래 항목을 순서대로 확인하세요.

점검 영역핵심 확인 사항
키 생성
  • 키, IV, Nonce, Salt 생성에 CSPRNG를 사용하는가?
  • 시간, PID, 카운터, 사용자 입력을 시드로 사용하지 않는가?
  • 테스트 키나 고정 키가 운영에 남아 있지 않은가?
키 관리
  • 키가 코드, 로그, 설정 파일, 이미지, Git 히스토리에 남지 않는가?
  • KMS/HSM/Secret Manager 등 전용 비밀 관리 체계가 있는가?
  • 키 회전, 폐기, 침해 시 재발급 절차가 있는가?
운영 모드
  • ECB 사용 여부를 확인했는가?
  • CBC라면 IV 예측 가능성과 MAC 보호 여부를 확인했는가?
  • CTR/GCM이라면 Nonce 재사용 가능성을 확인했는가?
인증 검증
  • 단순 해시가 아니라 MAC/AEAD 태그를 사용하는가?
  • 태그 검증 실패 시 평문을 완전히 폐기하는가?
  • 검증 실패 예외를 삼키고 후속 로직을 진행하지 않는가?
RSA 사용
  • 신규 암호화에 RSAES-PKCS1-v1_5를 사용하지 않는가?
  • 기존 v1.5 복호화 API가 oracle이 되지 않는가?
  • 암호화는 OAEP, 서명은 PSS 등 현대 권장 방식을 고려했는가?
비밀번호
  • 비밀번호를 복호화 가능한 형태로 저장하지 않는가?
  • Argon2id/bcrypt/scrypt/PBKDF2와 사용자별 Salt를 사용하는가?
  • 비용 파라미터가 현재 시스템 성능과 위협 모델에 맞는가?
리버싱/상호운용성
  • 알고리즘, 모드, 패딩, 인코딩, 엔디안 처리를 각각 분리해 확인했는가?
  • S-Box, 라운드 상수, 회전 연산, 키 스케줄 배열을 통해 알고리즘 식별을 교차 검증했는가?
  • 상수와 파라미터의 선택 근거가 공개 검증 가능하며, 수학적 백도어 의심 지점이 없는가?
  • 표준 테스트 벡터와 결과가 일치하는가?
  • 커스텀 래핑이 보안 경계를 약화시키지 않는가?

참고 기준