암호화
개요
암호화 기법이 어떻게 발전했는지 공부해보려고 한다.
암호
세계에서 가장 오래된 암호는 언제 나타났을까? 역사상 가장 오래된 암호는 기원전 500년경 스파르타에서 전쟁중 왕의 명령을 전할 때 사용했던 스키테일 암호라고 한다.
스키테일 암호는 긴 양피지를 스키테일(나무 막대)에 말아 가로로 읽어 해독하는 방식의 암호였다. 전쟁에 나가는 장군과 왕은 굵기가 같은 원통형 막대를 나눠 갖고 메시지를 전달해야할 때 원통에 둘둘 말아 그 위에 메시지를 적었다.
이때 원문은 지름이 비슷한 나무막대(암호키)가 없으면 해독할 수 없었다.(물론 다양한 지름을 가지는 나무막대를 하나씩 대보면 알 수 있을 것이다.) 이를 평범한 문장이나 그림 속에 암호문을 숨기는 스테가노 그래피라고 한다.
다른 종류의 암호도 있는데 치환암호다.
가장 유명한 암호는 바로 카이사르 암호로, 카이사르 암호는 로마의 황제 카이사르가 사용했던 치환 암호로 평문 알파벳을 일정한 간격(암호키)만큼 뒤로 밀어서 다른 알파벳으로 치환하는 방식이다.
예를 들어 키가 3이라면 A는 3번 뒤로 밀린 D가 된다.
그러나 영문에서 E,T,A가 가장 많이 나오는 알파벳이라는 점을 이용해 암호문에서 자주 등장하는 알파벳을 위의 3가지 알파벳으로 치환해보면 유추할 수 있었고 단순하게 알파벳을 하나씩 이동하며 시도하다보면 암호를 풀 수 있었다.
실제로 역사속에서 암호와 관련된 사건들이 많았는데 예를 들어 스코틀랜드의 메리 1세는 엘리자베스 1세 암살계획을 세우며 암호를 사용했는데 이것을 암호 해독관이 해석하여 결국 메리 1세는 처형되었다.
그러면 이런 생각을 해볼수도 있다. 암호화 방식을 알아도 키를 모르면 풀 수 없는 암호가 정말로 어려운 암호일 것이다.
맞다. 암호는 알고리즘보다 키가 중요하다. 알고리즘을 알아도 키를 모르면 풀 수가 없다.
대표적으로 이미테이션 게임에 나왔던 에니그마를 예로 들 수 있겠다.
영화를 보면 독일군의 무전을 도청하는데 알고리즘은 알아낼 수 있었으니 키를 몰라 치환 패턴을 알 수가 없었다.
그러다 키를 알아내어 암호를 해독하게 되었다고 한다.
여러 사례들을 봐도 암호문 그 자체보다 암호화 키가 더 중요하다.
이제 현대 암호에 대해 알아보자.
현대의 암호화는 대칭키 암호와 비대칭키 암호로 나뉜다.
대칭키 암호화는 암호화와 복호화에 같은 키를 사용하는 암호화 방식이다.
위에서 살펴본 스키테일 암호화 방식이나 카이사르 암호가 대칭키 암호화 방식에 해당한다.
대칭키 암호화
대칭키 암호화 방식은 속도가 빠르다는 특징이 있다.
그 이유는 기본적으로 대칭키는 XOR, 덧셈, 시프트, 치환, 순열과 같은 경량 연산을 반복한다. 이는 CPU레벨에서 매우 빠르게 처리 가능한 연산이라 속도가 빠른 것이다. 또한 AES와 같은 대표적인 대칭키 알고리즘은 CPU 제조사에서 AES-NI와 같은 하드웨어 가속 명령어를 제공하고 있고 대칭키는 데이터를 블록 단위 또는 스트림 단위로 처리하여 병렬화가 가능하다. 따라서 대량의 데이터에 유리하다.
이런 이유로 대량의 데이터나 네트워크에서 많이 사용된다.
다음의 코드는 대칭키 암호화 방식을 실습해 볼 수 있는 코드다.
# pip install cryptography
from cryptography.fernet import Fernet
# 1. 대칭키 생성
key = Fernet.generate_key()
cipher = Fernet(key)
print("생성된 키:", key.decode())
# 2. 메시지 암호화
message = "대칭키 암호화 실습 예제입니다.".encode()
encrypted_message = cipher.encrypt(message)
print("암호문:", encrypted_message.decode())
# 3. 암호문 복호화
decrypted_message = cipher.decrypt(encrypted_message)
print("복호문:", decrypted_message.decode())
비대칭키 암호화
비대칭키 암호화란 대칭키 암호화와 키가 두 개가 존재한다는 점에서 구별된다.
키의 종류는 2가지가 있는데 공개키와 개인키다.
공개키는 그 말 그대로 누구에게나 공개되어도 괜찮은 키고 개인키는 절대 노출하면 안되는 키다.
다음과 같은 동작을 한다.
- 공개키로 암호화 -> 개인키로만 복호화
- 개인키로 서명 -> 공개키로 검증 가능
대표적인 알고리즘으로는 RSA, ECC등이 있다.
RSA는 고안자 세 사람의 성에서 따왔다.
Rivest-Shamir-Adleman.
원리는 큰 수의 소인수분해가 어렵다는 수학적 사실에 기반하고 있다.
예를 들어 큰 소수 두 개를 선택한다. p, q(각각 수백 비트 이상)
그런 뒤 이 둘을 곱한다. n = p * q 이 때 n은 잠금장치와 같다.
그리고 누구나 사용할 수 있는 공개 열쇠를 하나 고른다. e라고 칭하겠다. 보통은 계산하기 쉬운 숫자(65537)를 사용한다.
이제 열쇠 2를 계산한다. 열쇠 2는 d라고 칭하겠다. 공개 열쇠와 딱 맞아떨어지는 비밀 열쇠로 수학적으로 짝이 되는 번호표라고 볼 수 있다.
정리해보면 위에서의 공개키에 해당하는 것이 (n, e), 그리고 개인키에 해당하는 것이 (n, d)가 된다.
핵심은 곱하기는 쉽다, 그러나 결과를 보고 소인수분해 하는 것은 어렵다는 원리다.
이런 비대칭키 암호화 방식은 보안이 강화된 대신 속도가 매우 느리다. 대략 대칭키에 비해 수천 수만 배까지도 느리다.
HTTPS
HTTPS는 이 둘을 조화롭게 사용하여 가능한 프로토콜이다.
- HTTP의 보안을 강화하기 위해 암호화를 고려했다.
- 대칭키가 빠르다는 점을 이용해 대칭키를 사용하여 암복호화 하여 서버와 통신한다.
- 그러나 대칭키도 결국 데이터이기 때문에 네트워크 상에서 공유가 일어난다.
- 대칭키 자체를 암호화 시키는 아이디어를 떠올렸다.
- 클라이언트가 서버를 호출한다. 그럼 서버는 공개키를 클라이언트에게 준다.
- 클라이언트는 이 공개키로 세션 대칭키를 암호화하여 서버로 보낸다.
- 이렇게 대칭키를 안전하게 공유했고 이제는 대칭키를 이용하여 송수신 데이터를 암호화하여 안전하게 통신할 수 있게 되었다.