암호화 기초와 현대 암호 기술

김경윤·2025년 5월 23일

정보보안

목록 보기
9/10
post-thumbnail

암호의 기초

암호화 과정

  • 암호(Cryptography) : 중요 정보를 다른 사람들이 해석할 수 없게 하는 방법
  • 평문(Plain Text) : 암호화되기 전의 메시지
  • 암호문(Cipher Text) : 암호화되고 난 후 변경된 메시지
  • 암호화 또는 암호화 과정 : 평문을 암호문으로 바꾸는 과정
  • 암호화 알고리즘 : 평문을 어떤 방식으로 암호문으로 변경할지 결정
  • 암호화 키(Encryption Key) : 허락받지 않은 외부인이 암호문을 강제적으로 해독(Crypt-analysis)하는
    것을 막음


복호화 과정

  • 복호화(Decrypt): 암호문을 복호화 키(Decryption Key)를 이용하여 평문으로 바꾸는 과정

  • 암호화 방식 비교
구분대칭 암호화 알고리즘비대칭 암호화 알고리즘
키의 상호 관계암호화 키 = 복호화 키암호화 키 ≠ 복호화 키

암호의 역사 : 고전 암호학

스키테일(Scytale) 암호

  • BC400년 스파르타에서 군사용으로 사용하던 암호화 방식
  • 전치법(Transposition) 알고리즘 : 특정 순서에 따라 평문 배열을 재조정


시저 암호

  • BC100년경에 로마의 줄리어스 시저가 군사적인 목적으로 사용한 암호
  • 단일 치환(Mono-Alphabetic Substitution) 알고리즘: 알파벳 한 글자를 다른 한 글자로 대체
  • 전사 공격 (Brute-force Attack) 에 취약


단일 치환 암호: 모노 알파베틱 (Mono-alphabetic) 암호

  • 알파벳 26글자를 각각 다른 알파벳에 대응시키는 방식으로 암호화
  • 단일 치환 암호 방식이지만, 알고리즘의 개선을 통해 보안성을 강화시킴
  • 전사 공격에 다소 강하기 때문에, 10세기까지 사용됨
  • 빈도 분석법(Frequency Analysis)에 취약


다중 치환(Polygram Substitution)

  • 한 글자가 암호화 키와의 매핑에 따라 여러 가지 글자로 대체되어 암호화되는 방식
  • 대표적인 예: 비즈네르(Vigenere) 암호

  • 암호화의 예
  • 암호화하려는 단어: aaa
  • 암호화 키: BDG
  • 빈도 분석법(Frequency Analysis)에 다소 강함
  • 플레이페어(Playfair) 암호, 에니그마(Enigma) 등으로 발전됨
  • 컴퓨터의 고속 병렬 처리 연산 등으로 현대에는 해독이 비교적 어렵지 않게 가능해짐


대칭 암호화 방식

DES

  • 대칭키(Symmetric key) 암호화 방식
  • 암호화 키와 복호화 키가 같은 암호화 방식
  • 암호화 및 복호화에 걸리는 시간이 짧으며, 비교적 간단한 방식으로 구현 가능
  • 현대에 가장 많이 사용되는 암호 방식 중 하나
  • DES(Data Encryption Standard)
  • 1997년 미국의 연방 정보의 표준 암호로 채택됨
  • 64비트 평문을 64비트 암호문으로 암호화
  • 키의 크기: 56비트(오류 검출을 위해 8비트가 사용)
  • 전사 공격으로 DES의 해독이 가능해짐에 따라, 1998년 11월 이후 공식적 사용 중단

암호화 과정 개요

  • 전처리(Pre-Processing) 단계: 초기 치환(Initial Permutations) 실행
  • 16번의 라운드 (Round) 수행
  • 후처리(Post-Processing) 단계: 최종 치환(Final Permutations)


1 라운드

  • 64비트를 왼쪽 L(32비트)과 오른쪽 R(32비트)로 나눔
  • L은 F와의 논리합을 계산
  • R은 기존의 값을 그대로 사용
  • L과 R의 위치를 바꿈


2~17 라운드

  • 이전 라운드에서 만들어진 L과 R을 사용
  • 암호화 키 K에서 만들어진 F() 함수와 논리합 연산
  • L과 R 위치를 서로 바꿈


마지막 라운드

  • 중간 연산은 앞의 라운드와 같음
  • 최종적으로 계산된 L과 R을 합쳐서 하나의 블록으로 만듦


트리플 DES(Triple DES)

  • DES의 대안으로 제시된 DES의 비도(암호화 강도)를 강화한 대칭키 암호 방식
  • DES를 3번 연속 실행, 삼중 DES 혹은 3DES라고도 불림
  • 2번의 DES 암호화 중간에 DES 복호화가 1번을 실행함
  • 기존 DES와의 호환성 유지 목적
  • 수학적으로 DES 알고리즘보다 2배의 암호화 강도를 가진다고 평가
  • 충분한 암호 강도가 아니기 때문에, AES가 권장됨


AES(Advanced Encryption Standard)

  • 1997년 미국 NIST의 암호 공모에서 새로운 대칭 암호의 표준으로 채택된 대칭키 암호 방식
  • 암호 공모 조건
    • 안전성(Security)
    • 비용(Cost)
    • 구현 효율성(Implementation)
  • 특징
    • 128비트 평문을 128비트 암호문으로 암호화
    • 키의 크기: 3가지 (128, 192, 256비트)
    • 10번의 라운드 (Round) 수행


AES의 각 라운드 구성

  • 대치(Substitution) 연산 – SubBytes
    • S-box를 이용해 치환
  • 치환(Permutation) 연산 – ShiftRows
    • 각 행의 기준에 따라 왼쪽으로 shift
  • 혼합(Mixing) 연산 – MixColumns
    • 열 단위 연산 수행(constant matrix를 곱함)
  • AddRoundKey 연산
    • 열단위로 라운드 키를 더함

  1. 첫 번째 라운드 시작 전, AddRoundKey 연산을 한 번 수행한다.
  2. 마지막 라운드에서는 세 번째 연산인 MixColumns수행하지 않는다.

그 밖의 대칭 암호

  • SEED
    • 국산 128비트 블록 암호 알고리즘
    • 전자상거래, 금융, 무선통신 등에서 전송되는 중요 정보 보호 목적
    • SEED 128 - 128비트 키, SEED 256 - 256비트 키
  • ARIA
    • 국산 128비트 블록 암호화 알고리즘
    • 경량 환경 및 하드웨어에서의 효율성 향상을 위해 개발
    • AES와 마찬가지로 128/192/256비트 암호화 키를 지원
  • IDEA - 유럽에서 많이 사용
  • RC5 - 미국 RSA 연구소에서 개발

블록 암호 모드

  • 대칭 암호화 방식은 하나의 평문을 블록 단위로 나누어서 암호화 또는 복호화를 수행
    • 예) 300비트 평문을 AES로 암호화 하는 경우
      → AES의 블록 크기: 128비트
      블록 개수: 3개
      3번째 블록에 저장되는 데이터 크기: 44비트
  • 패딩(Padding): 블록의 남은 부분에 데이터를 채워 넣는 것

  • ECB(Electric Code Book) 모드
    • 각 평문 블록을 암호화한 것이 그대로 암호문 블록이 되는 방식
    • 장점 - 계산이 단순
    • 단점 – 보안적으로 취약 (변조 가능)
      → 중간 블록을 단순히 바꿔치기만 해도 동작함

  • CBC(Cipher Block Chaining) 모드
    • 암호문 블록을 마치 체인처럼 연결하는 모드
      → 현재의 평문 블록과 현재 블록 바로 직전에 암호화된 암호 블록을 XOR 연산한 후 암호화
    • 초기화 벡터(IV: Initial Vector): 최초 블록을 암호화할 때 XOR 연산에 사용되는 블록
    • 장점 - 보안적으로 안전 (변조 불가)
    • 단점 - 계산이 다소 복잡
      ☞ 제약사항 : 중간에 있는 블록을 복호화하기 위해서
      반드시 첫 블록부터 복호화를 해야함

구분장점단점비고
ECB 모드- 간단
- 병렬 처리 가능 (암호화, 복호화 모두)
- 평문의 반복이 암호문에 반영됨
- 암호문 블록의 삭제/교체에 취약
- 평문 변조 가능
보안상 취약함
사용 권장하지 않음
CBC 모드- 평문 반복이 암호문에 반영되지 않음
- 암호문 블록 삭제/교체에 의한 평문 변조 불가
- 암호화 시 병렬 처리 불가능권장

비대칭 암호화 방식

  • 비대칭 암호화 방식의 필요성
  • 대칭 암호화 방식의 '키 배포' 문제에 대한 보완책 필요


디피-헬만 키 교환(Diffie–Hellman Key Exchange)

  • 소수(prime)를 이용한 나머지(mod) 연산을 사용
    → 통신을 통해 미리 배포되지 않은 새로운 비밀키 s를 공유하는 것이 목표
  • 과정
    ① 공개된 숫자 p와 g 설정
    ② 앨리스 : 자신의 개인키 a에서 숫자 A를 계산
    ③ 밥 : 자신의 개인키 b에서 B를 계산
    ④ 앨리스 : 밥이 전달한 B와 자신의 개인키 a를 이용하여 비밀키 s를 계산
    ⑤ 밥 : 앨리스가 보내준 A와 자신의 개인키 b를 이용하여 비밀키 s를 계산


🔐 디피-헬만 키 교환 절차 요약

  1. 공개 설정

    • 공개 소수 p=23p = 23, 생성자 g=5g = 5
    • 앨리스의 개인키 a=6a = 6, 밥의 개인키 b=15b = 15
  2. 앨리스의 계산

    • A=gamodp=56mod23=8A = g^a \mod p = 5^6 \mod 23 = 8
  3. 밥의 계산

    • B=gbmodp=515mod23=19B = g^b \mod p = 5^{15} \mod 23 = 19
  4. 앨리스의 비밀키 계산

    • S=Bamodp=196mod23=2S = B^a \mod p = 19^6 \mod 23 = 2
  5. 밥의 비밀키 계산

    • S=Abmodp=815mod23=2S = A^b \mod p = 8^{15} \mod 23 = 2

결과: 두 사람의 비밀키가 동일하게 2로 일치!
→ 제3자 없이 안전하게 공통 비밀키 공유 성공


RSA

비대칭 암호화 방식 1

  • 공개키로 암호화, 개인키로 복호화
  • 암호화된 메시지는 밥의 개인키로만 복호화 가능 → 기밀성 보장
  • 다른 사람이 중간에서 도청할 수 없음
  • 중간에서 편지를 가로챘더라도 암호화된 메시지를 복호화할 수 없음


비대칭 암호화 방식 2

  • 개인키로 암호화, 공개키로 복호화
  • 앨리스의 공개키로만 복호화 가능 → 부인 방지 (Non-repudiation) 보장
  • 앨리스가 자신이 보낸 사실을 ‘부인’ → 앨리스의 공개키로만 복호화가 가능하다는 사실을 통해 ‘부인’에
    대한 증거를 제시
  • 전자상거래에서 기업 간 주문이나 계약에서도 중요한 법적 증거 역할


🔐 RSA 키 생성 과정

✅ Step 1. 큰 소수 ppqq를 선택해 곱한다

  • 두 개의 서로 다른 큰 소수 pp, qq를 랜덤하게 선택

  • 이 둘을 곱해서 NN을 만든다:

    N=p×qN = p \times q
  • NN은 나중에 공개키와 개인키에 공통으로 사용

  • 예시:
    p=61, q=53N=61×53=3233p = 61, \ q = 53 \Rightarrow N = 61 \times 53 = 3233


✅ Step 2. 오일러 피 함수(ϕ) 계산

  • RSA에서는 ϕ(N)\phi(N) = (p1)(q1)(p-1)(q-1)을 사용

    ϕ(N)=(p1)×(q1)\phi(N) = (p-1) \times (q-1)
  • 예시:
    (611)×(531)=60×52=780(61-1) \times (53-1) = 60 \times 52 = 780


✅ Step 3. 공개키 지수 ee 선택

  • 1<e<ϕ(N)1 < e < \phi(N) 사이의 수 중에서
    ϕ(N)\phi(N)과 서로소인 수를 하나 선택
    → 서로소: 최대공약수가 1인 수

  • ee는 나중에 **공개키 (e, N)**로 사용됨

  • 예시:
    e=19e = 19 (780과 서로소)


✅ Step 4. 개인키 dd 계산

  • dde×d1modϕ(N)e \times d \equiv 1 \mod \phi(N)을 만족하는 수

  • 즉, dd는 **ee**의 모듈로 역원 (modular inverse)

  • 유클리드 알고리즘으로 계산하거나 직접 찾아도 됨

  • 예시:
    e=19e = 19, ϕ(N)=780\phi(N) = 780
    19×d1mod78019 \times d \equiv 1 \mod 780
    d=739d = 739 이 만족함


🔑 최종 키 구성

  • 공개키 (e, N) = (19, 3233)
    → 누구에게나 알려도 됨

  • 개인키 (d, N) = (739, 3233)
    → 절대 유출되면 안 됨


🔐 RSA 암호화와 복호화 방식

✅ 공개키로 암호화하기

  • 공식:

    c=memodNc = m^e \mod N

    여기서,

    • mm: 평문 메시지
    • ee: 공개키 지수
    • NN: 공개 모듈러 값
    • cc: 암호문
  • 예시:

    • 평문 m=65m = 65
    • 공개키 (e,N)=(19,3233)(e, N) = (19, 3233)
    c=6519mod3233=232c = 65^{19} \mod 3233 = 232

✅ 개인키로 복호화하기

  • 공식:

    m=cdmodNm = c^d \mod N

    여기서,

    • cc: 암호문
    • dd: 개인키 지수
    • NN: 공개 모듈러 값
    • mm: 복호화된 평문
  • 예시:

    • 암호문 c=232c = 232
    • 개인키 (d,N)=(739,3233)(d, N) = (739, 3233)
    m=232739mod3233=65m = 232^{739} \mod 3233 = 65

결과 요약

  • 평문 65 → 암호화 → 232
  • 암호문 232 → 복호화 → 65

→ 암호화-복호화가 정확히 동작함을 확인!
이것이 RSA의 핵심 원리입니다.


그 외의 비대칭 암호화 방식들

  • 타원 곡선 암호(ECC: Elliptic Curve Cryptosystems)
    • RSA에 비해 키의 크기가 작으면서도 높은 보안성을 제공 가능
      • RSA의 키 크기가 1,024비트인 보안 수준 → ECC: 160비트 정도 (RSA의 약 1/6)
    • 암호화 및 복호화 속도가 RSA보다 빠름
    • 자원 사용 효율성이 높아 작은 하드웨어(스마트카드, 휴대전화)에서도 잘 동작
  • 그 외
    • 엘가말(ElGamal)
    • 라빈(Rabin)

🔒 암호화 방식 비교

항목대칭 암호화 방식비대칭 암호화 방식
키의 상호 관계암호화 키 = 복호화 키암호화 키 ≠ 복호화 키
안전한 키 길이128비트 이상2048비트 이상
키의 구성비밀키공개키, 개인키
예시 알고리즘DES, 3DES, AESRSA, ECC
제품 서비스기밀성기밀성, 부인 방지, 인증
목적데이터 암호화키 교환
단점별도의 키 교환 필요공개키가 노출되면 중간자 공격에 취약
암호화 속도빠르다느리다
  • 대칭키: 빠르고 간단하지만 키 교환이 문제
  • 비대칭키: 안전하게 키를 교환할 수 있지만 속도가 느림

전자서명

개념

  • 서명(Signature)
  • 누군가가 문서를 기록했다는 증거
  • 역할 : 서류에 대한 인증 및 부인방지
  • 일반 종이 서류 : 서명자가 손으로 직접 적은 싸인 혹은 도장이 서명 역할


개념: 개인키로 암호화, 공개키로 복호화

  • 전자서명(Digital signature): 원본 메시지에 대한 해시 값을 서명자의 개인키로 암호화하는 것
  • 제공 기능: 메시지에 대한 인증, 부인방지 및 메시지 무결성 검증
    → 오직 수신자의 개인키로만 복호화할 수 있기 때문에 가능

🔐 해시 함수

  • 정보의 무결성(Integrity) 확인을 위한 목적으로 사용
  • 입력 데이터를 고정된 길이의 해시값으로 변환
  • 해시값만 보고 원래 입력을 역으로 추정하는 것은 계산상 불가능
  • 동일한 입력 → 항상 동일한 해시값
  • 아주 작은 입력 변화 → 완전히 다른 해시값 (눈사태 효과)

✅ 대표적인 해시 알고리즘 예시

  • MD5
  • SHA-1
  • SHA-256
  • SHA-3

공개키 기반 구조

  • 전자서명의 약점
    • 전자서명을 할 때 사용된 공개키가 정말로 송신자의 공개키인지 증명 필요
  • 공개키 인증서(PKC, Public Key Certificate)
    • 신뢰할 수 있는 인증 기관(CA, Certification Authority)을 이용하여 신뢰할 수 있는 안전한 공개키를 제공
  • 공개키 기반 구조(PKI: Public Key Infrastructure)
    • 공개키를 효과적으로 사용하여 안전한 암호화와 전자서명 기능 등을 제공하는 보안 환경(예: 인터넷 뱅킹에서
      사용되는 공인인증서)


구성요소주요 기능
인증기관(CA)인증 정책 수립, 인증서 관리, 인증서 폐기 목록 등록/관리/인증
Certification Authority
등록기관(RA)사용자 신원 확인, 인증서 요구 승인, CA에 인증서 발급 요청, 인터페이스 제공
Registration Authority
검증기관(VA)인증서 유효성 검증/확인 주체
Validation Authority
인증서 폐기 목록(CRL)인증서 폐기 목록, 인증서 유효성 점검
Certification Revocation List
디렉터리 서비스인증서, 암호키에 대한 저장/검색/관리
인증서(X.509)CA가 발행한 공개키 인증서 표준 포맷


인증서 사용 방법

  • 공개키 인증서(Public Key Certificate): 사용자의 공개키에 사용자의 식별 정보를 추가하여 만든
    일종의 전자 신분증

인증서 사용 Step 1: 인증서 등록 및 배포


인증서 사용 Step 2: 인증서 검증 및 공개키 사용


ⓐ 앨리스가 받은 밥의 공개키 확인 과정


ⓑ 인증서 연결 구조

  • 검증 방법
    • 발급 기관의 이름을 추적하여 최상위 기관의 인증서를 찾음
    • 그 후, 발급자 서명과 상위 기관 인증서의 공개키를 이용해 인증서 해시값 검증
  • 신뢰체인: 각 인증서가 서로 신뢰 관계에 있는 상태


공개키 기반 구조 - 상호인증

상호인증(Crosscertification)

  • 두 인증기관이 상대방의 공개키를 서로 인증해주는 인증서를 발급하여 사용하는 것
  • 상호인증서(cross-certificate)


대칭키

  • 대칭키는 암호화, 복호화에 사용하는 키가 동일함
  • 비대칭키 암호화 방식에 비해 속도가 빠름
  • 키 교환 과정에서 탈취, 노출 등의 위험이 있음
  • 통신 상대가 많아지면 전부 키를 교환해야 하기 때문에 관리할 키가 많아 짐

from cryptography.fernet import Fernet

# 키 생성
key = Fernet.generate_key()
print(f"[key] {key}")
cipher_suite = Fernet(key)

# 암호화
text = b"Hello, cryptography!"
cipher_text = cipher_suite.encrypt(text)
print(f"Cipher Text: {cipher_text}")

# 복호화
decrypted_text = cipher_suite.decrypt(cipher_text)
print(f"Decrypted Text: {decrypted_text}")

pip install cryptography


대칭키(AES)

다음은 이미지에 나온 파이썬 AES 암호화/복호화 코드입니다:

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

# 암호화 키 생성
key = get_random_bytes(16)

# 암호화 객체 생성
cipher = AES.new(key, AES.MODE_EAX)

# 암호화할 데이터
data = b"Secret Message"

# 데이터 암호화
ciphertext, tag = cipher.encrypt_and_digest(data)

# 복호화 객체 생성
cipher_dec = AES.new(key, AES.MODE_EAX, cipher.nonce)

# 데이터 복호화
decrypted_data = cipher_dec.decrypt_and_verify(ciphertext, tag)

print("Original:", data)
print("Decrypted:", decrypted_data)

pip install pycryptodome


비대칭키

  • 비대칭키는 암호화, 복호화에 사용하는 키가 다름
  • 송신자, 수신자 모두 한 쌍의 키(개인키, 공개키)를 갖음
  • 개인키는 비공개, 공개키는 모든 사람이 접근 가능(공개)
  • 키 분배 및 키 관리가 용이
  • 기밀성, 무결성, 부인 방지 제공
  • 키 길이가 길고, 대칭키에 비해 암호화 속도가 느림

from nacl.public import PrivateKey, Box

# 공개키/비밀키 쌍 생성
sk = PrivateKey.generate()
pk = sk.public_key

# 수신자의 공개키/비밀키 쌍 생성
receiver_sk = PrivateKey.generate()
receiver_pk = receiver_sk.public_key

# 송신자의 Box 생성
sender_box = Box(sk, receiver_pk)

# 메시지 암호화
message = b"Hello PyNaCl"
encrypted = sender_box.encrypt(message)

# 수신자의 Box 생성
receiver_box = Box(receiver_sk, pk)

# 메시지 복호화
decrypted = receiver_box.decrypt(encrypted)

print("Encrypted message:", encrypted)
print("Decrypted message:", decrypted)

pip install pynacl


비대칭키 적용

echo_client2_py

from nacl.public import PrivateKey, PublicKey, Box
import socket

sk = PrivateKey.generate()
pk = sk.public_key

sock = socket.socket()
sock.connect(("127.0.0.1", 9999))

# 클라이언트 공개키 전송
sock.sendall(pk.encode())

# 서버 공개키 수신
receiver_pk = PublicKey(sock.recv(1024))

sender_box = Box(sk, receiver_pk)

while True:
    message = input("입력: ")
    encrypted = sender_box.encrypt(message.encode())
    print("[A] 암호화 메시지:", encrypted)

    sock.sendall(encrypted)

    if message == "end":
        break

sock.close()

echo_server2_py

from nacl.public import PrivateKey, PublicKey, Box
import socket

# 수신자(B)의 비밀키 및 공개키 생성
receiver_sk = PrivateKey.generate()
receiver_pk = receiver_sk.public_key

with socket.socket() as s:
    s.bind(("", 9999))
    s.listen()
    print("서버 대기 중...")

    conn, addr = s.accept()
    print("클라이언트 연결됨:", addr)

    # 클라이언트(A)의 공개키 수신
    client_pk_bytes = conn.recv(1024)
    client_pk = PublicKey(client_pk_bytes)

    # 서버(B)의 공개키 전송
    conn.sendall(receiver_pk.encode())

    # Box 생성 (서버의 비밀키, 클라이언트의 공개키)
    receiver_box = Box(receiver_sk, client_pk)

    while True:
        try:
            encrypted = conn.recv(4096)
            if not encrypted:
                break

            # 복호화
            decrypted = receiver_box.decrypt(encrypted)
            print("[B] 암호화 메시지:", encrypted)
            print("[B] 복호화 메시지:", decrypted.decode())

            # 종료 조건
            if decrypted.decode() == "end":
                break

        except Exception as e:
            print("복호화 실패:", e)
            break


0개의 댓글