암호학: 치환기법, 전치기법

암호학 치환기법과 전치기법입니다. 시저 암호 수식, 단일 치환, Playfair, columnar transposition과 Python 실습 예제를 정리했습니다.

암호학: 치환기법, 전치기법

치환과 전치는 고전 암호를 이해할 때 가장 먼저 보는 두 가지 변환 방식이다. 치환은 문자를 다른 문자로 바꾸고, 전치는 문자의 위치를 바꾼다. 현대 암호는 훨씬 복잡하지만, 혼돈(confusion)과 확산(diffusion)을 설명할 때 이 두 개념이 기본 재료가 된다.

시저 암호

시저 암호는 알파벳을 일정한 간격만큼 밀어서 치환한다. 키가 3이면 ad, be가 된다. 영문 알파벳 26자를 기준으로 하면 암호화와 복호화는 다음처럼 표현할 수 있다.

Encryption: C = E(p) = (p + k) mod 26
Decryption: p = D(C) = (C - k) mod 26
plain : meet me after the toga party
key   : 3
cipher: phhw ph diwhu wkh wrjd sduwb

키 공간이 25개뿐이므로 시저 암호는 학습용으로만 다룬다. 공격자가 알고리즘을 알고 있고 평문 언어가 영어라는 사실까지 안다면 전수조사와 빈도 분석으로 쉽게 깨진다.

Python으로 시저 암호 확인

import string

ALPHABET = string.ascii_lowercase

def caesar(text: str, key: int) -> str:
    out = []
    for ch in text.lower():
        if ch in ALPHABET:
            idx = ALPHABET.index(ch)
            out.append(ALPHABET[(idx + key) % 26])
        else:
            out.append(ch)
    return "".join(out)

plain = "meet me after the toga party"
cipher = caesar(plain, 3)
restored = caesar(cipher, -3)

print(cipher)
print(restored)
python3 caesar.py

단일 치환 암호

단일 치환은 알파벳 전체를 임의의 치환표로 바꾼다. 시저 암호보다 키 공간은 훨씬 커지지만, 하나의 평문 문자가 항상 같은 암호문 문자로 바뀌기 때문에 언어의 빈도 특성이 남는다. 예를 들어 영어 문장에서는 e, t, a 같은 문자의 빈도가 높고, th, he, in 같은 이중자 패턴도 단서가 된다.

plain alphabet : abcdefghijklmnopqrstuvwxyz
cipher alphabet: qwertyuiopasdfghjklzxcvbnm

Playfair 같은 다중 문자 치환

Playfair는 두 글자씩 묶어 치환하는 방식이다. 5x5 표를 만들고, 보통 ij를 같은 칸으로 취급한다. 같은 행이면 오른쪽 글자로, 같은 열이면 아래 글자로, 둘 다 아니면 사각형의 반대 꼭짓점 글자로 치환한다.

keyword: monarch

m o n a r
c h y b d
e f g i k
l p q s t
u v w x z

한 글자 단위 빈도 분석은 어렵게 만들지만, 긴 암호문에서는 여전히 구조가 남는다. 따라서 현대 보안 용도로 쓰는 방식은 아니다.

전치 기법

전치 암호는 글자를 바꾸지 않고 위치만 바꾼다. 예를 들어 열 개수를 6으로 잡고 문장을 행 단위로 채운 뒤, 열 순서를 1 4 2 5 3 6처럼 바꿔 읽을 수 있다.

key order: 1 4 2 5 3 6
plain    : you need ream before the day begins
import math

def columnar_transpose(text: str, order: list[int]) -> str:
    clean = "".join(ch for ch in text.lower() if ch.isalpha())
    width = len(order)
    height = math.ceil(len(clean) / width)
    padded = clean.ljust(width * height, "x")
    rows = [padded[i:i + width] for i in range(0, len(padded), width)]

    result = []
    for col in order:
        result.extend(row[col - 1] for row in rows)
    return "".join(result)

print(columnar_transpose("you need dream before the day begins", [1, 4, 2, 5, 3, 6]))

정리

  • 치환은 값을 바꾸고, 전치는 위치를 바꾼다.
  • 시저 암호는 수식 이해용으로 적합하지만 키 공간이 너무 작다.
  • 단일 치환은 빈도 분석에 약하다.
  • Playfair는 두 글자 단위라 단일 문자 빈도 분석은 어렵지만 현대 보안 기준에는 맞지 않는다.
  • 현대 블록 암호는 치환과 전치 아이디어를 더 복잡한 라운드 구조 안에서 사용한다.
BGM EVER