1. 암호의 기초
1) 암호화 과정
- 암호 : 중요 정보를 다른 사람들이 해석할 수 없게 하는 방법
- 평문 : 암호화되기 전의 메시지
- 암호문 : 암호화되고 난 후 변경된 메시지
- 암호화 : 평문을 암호문으로 바꾸는 과정
- 암호화 알고리즘 : 평문을 어떤 방식으로 암호문으로 변경할지 결정
- 암호화 키 : 허락받지 않은 외부인이 암호문을 강제적으로 해독하는 것을 막음
2) 복호화 과정
- 복호화 : 암호문을 복호화 키를 이용하여 평문으로 바꾸는 과정
- 암호화 방식 비교
ㆍ 대칭 암호화 알고리즘 : 암호화 키 = 복호화 키
ㆍ 비대칭 알고리즘 : 암호화 키 != 복호화 키
2. 암호의 역사 : 고전 암호학
1) 스키테일 암호
- 고대 스파르타에서 군사용으로 사용한 암호화 방식
- 전치법 알고리즘 : 특정 순서에 따라 평문 배열을 재조정, 평문 문자는 그대로 두고 배열 순서만 바꾸는 방식
- 키 : 나무 막대의 굵기
ㆍ 같은 굵기의 막대기에 종이를 감아야 평문이 보임
ㆍ 다르면 글자가 맞지 않아 복호화가 어려움 - 글자를 어떻게 섞느냐가 중요함
2) 시저 암호
- 로마의 줄리어스 시저가 군사 목적으로 사용한 암호
- 단일 치환 알고리즘 : 알파벳을 다른 글자로 대체, 일정한 칸 수(키)만큼 밀어서 다른 글자로 변경
- ex) 키가 3이라면, C는 3칸 밀려 F가 됨
ㆍ COME TO ROME → FRPH WR URPH - 항상 키만큼의 알파벳으로 바뀌기 때문에 전사 공격에 취약함
ㆍ 전사 공격 : 브루트포스, 하나씩 다 해보는 공격
3) 단일 치환 암호(모노 알파베틱)
- 시저 암호보다는 복잡함
- 알파벳 26글자를 각각 다른 알파벳에 대응시키는 방식으로 암호화
- 알파벳별로 대응표를 만들어서 암호화
- 시저 암호보다 보안성은 높음
- 빈도 분석법에 취약함
4) 다중 치환
- 단일 치환은 항상 같은 글자로 변경됨, 이를 보완
- 같은 글자라도 위치나 키에 따라 여러 가지 글자로 대체되어 암호화됨
- 대표적인 예 : 비즈네르 암호
ㆍ 키 문자에 따라 다른 줄의 치환표를 사용 - 빈도 분석법에 강함
- ex) aaa가 표에 따라 BDG로 암호화됨
3. 대칭 암호화 방식
1) DES(Data Encryption Standard)
- 대칭키 암호화 방식
- 암호화 키 = 복호화 키
- 암호화 및 복호화에 걸리는 시간이 짧으며, 비교적 간단한 방식으로 구현 가능, 현대에 가장 많이 사용
- 64비트 평문을 64비트 암호문으로 암호화
- 키는 56비트이고, 8비트는 오류 검출용 패리티 비트
- 암호화 과정
ㆍ 전처리 단계 : 초기 치환 실행 → 16번의 라운드 실행 → 후처리 단계 : 최종 치환
ㆍ 1라운드 : 64비트를 L(32비트), R(32비트)로 나눔- L은 서브키가 포함된 라운드 함수 F와의 논리합 계산(XOR 연산)
- R은 그대로 사용
- 다음 라운드로 넘어가기 전 L과 R의 위치 변경
- 이 과정을 16라운드 거치며 마지막 라운드에서 합침
2) 트리플 DES
- DES의 암호화 강도를 강화한 방식
- DES를 3번 연속 실행(= 3DES)
- 암호화 과정
ㆍ 평문 → K1 암호화 → K2 복호화 → K3 암호화 → 암호문
ㆍ 2번의 암호화와 복호화 1번을 진행함
ㆍ 호환성 유지 목적 - 복호화 과정
ㆍ 암호문 → K3 복호화 → K2 암호화 → K1 복호화 → 평문
ㆍ 암호화의 반대로 처리 - DES보다 2배의 암호화 강도를 가진다고 하지만, 충분한 암호 강도가 아니라 AES가 권장됨
3) AES
- 미국 NIST의 암호 공모에서 채택된 대칭키 암호 방식
- 암호 공모 조건
ㆍ 안전성
ㆍ 비용
ㆍ 구현 효율성 - 128비트 평문을 128비트 암호문으로 암호화
- 키 길이 : 128, 192, 256비트
- 10번의 라운드 수행
- 암호화 과정
ㆍ 대치 연산 : 입력 바이트를 S-box를 통해 다른 바이트로 대체
ㆍ 치환 연산 : 행을 왼쪽으로 shift, 같은 줄에 있던 데이터 위치를 바꿔 전체적으로 섞음
ㆍ 혼합 연산 : 열 단위로 데이터 섞음
ㆍ AddRoundKey 연산 : 현재 State와 라운드 키를 XOR하는 과정 - 이 과정이 하나의 라운드임
- 첫 번째 라운드 시작 전 AddRoundKey 연산을 한 번 수행
- 마지막 라운드에서는 혼합 연산 수행 안 함
ㆍ 모든 라운드가 같지 않음
4) SEED
- 국산 128비트 블록 암호 알고리즘
- 전자상거래, 금융 등 중요 정보 보호 목적
- SEED-128, SEED-256
5) ARIA
- 국산 128비트 블록 암호화 알고리즘
- 경량 환경 및 하드웨어에서의 효율성 향상을 위해 개발
6) 그 외
- IDEA, RC5
7) 블록 암호 모드
- 대칭 암호화 방식은 평문을 정해진 크기의 블록 단위로 나누어 암호화
- ex) 300비트를 128비트 블록으로 나눔
ㆍ 1번째 블록 : 128비트
ㆍ 2번째 블록 : 128비트
ㆍ 3번째 블록 : 44비트
ㆍ 같은 크기로 나누다 보니 부족한 부분이 생김 → 패딩 - 패딩 : 블록의 남은 부분에 데이터를 채워 넣는 것
ㆍ 44비트에 84비트를 패딩하여 128비트 블록을 만듦
(1) ECB 모드
- 각 평문 블록을 암호화한 것이 그대로 암호문 블록이 되는 방식
- 암호화, 복호화 모두 병렬 처리 가능
- 계산이 단순하지만 같은 평문이 같은 암호문으로 나오기 때문에 보안적으로 취약함
- 평문의 반복이 암호문에 반영됨
- 중간 암호문 블록의 삭제 혹은 교체에 의해 평문 변조 가능
(2) CBC 모드
- 암호문 블록을 체인처럼 연결하는 방식
- 현재 평문 블록을 바로 암호화하는 것이 아닌, 이전 암호문 블록과 XOR 연산 후 암호화
- 초기화 벡터 : 첫 번째 블록은 암호문 블록이 없기에, 최초 블록 XOR 연산에 사용되는 블록
- 보안적으로 안전하지만, 계산이 복잡함
- 암호화 과정
ㆍ 현재 평문 블록 ⊕ 이전 암호문 블록 → 암호화 → 암호문 블록 - 제약사항 : 중간에 있는 블록 복호화를 위해 반드시 처음부터 복호화해야 함
- 암호화에서 병렬 처리가 불가능
4. 비대칭 암호화 방식
- 필요한 이유 : 대칭 암호화 방식은 키 배포 문제가 있음, 키가 노출되면 누구나 복호화 가능
1) 디피 - 헬만 키 교환
- 비밀키를 직접 보내는 것이 아닌, 통신을 통해 비밀키를 공유하는 방법
- 소수를 이용한 나머지 연산을 사용
- 계산식 : 공개된 숫자 p와 g 설정, 개인키는 a, b라고 가정
- ㆍ A = g^a mod p, B = g^b mod p 로 계산한 A, B를 서로에게 전달
- ㆍ a의 비밀키 S = B^a mod p, B의 비밀키 S = A^b mod p
=> 비밀키를 직접 보내지 않아도 같은 비밀키를 구할 수 있음
2) RSA
- 비대칭 암호화 방식
- DH 키 교환에서 사용된 비대칭 알고리즘에 기반을 둔 암호화 방식
- 공개키 : 외부에 공개할 수 있는 키(개인키를 통해 만듦)
- 개인키 : 자신만 알아야하는 키
(1) 비대칭 암호화 방식 1
- 공개키로 암호화, 개인키로 복호화
- 암호화된 메시지는 개인키로만 복호화 가능 → 기밀성 보장
- 다른 사람이 중간에 도청 불가능
- ex) 엘리스가 밥의 공개키로 암호화 → 밥이 자신의 개인키로 복호화
(2) 비대칭 암호화 방식 2
- 개인키로 암호화, 공개키로 복호화
- 부인 방지 보장 : 공개키로 복호화가 가능하다는 것은 개인키로 만들어졌다는 증거가 되어, 보낸 사실을 부정하지 못하게 함
- 전자상거래나 계약에서 중요한 법적 증거 역할
(3) 암호화와 복호화 방법
- 평문 m을 암호화하여 c를 계산, 공개키 (E,N) : m^E mod N
- 암호문 c를 복호화하여 m 계산, 개인키 (D,N) : c^D mod N
3) 그 외 비대칭 암호화 방식
- 타원 곡선 암호(ECC) : RSA에 비해 작은 크기로 높은 보안성 제공, 키 크기가 작아 빠름, 자원 효율성 높아 작은하드웨어(휴대전화, 스마트카드)에서도 동작
- 엘가말, 라빈
4) 암호화 방식 비교 : 대칭 vs 비대칭
- 안전한 키 길이 : 128비트 이상 || 2048비트 이상
- 키의 구성 : 비밀키 || 공개키,개인키
- 제공 서비스 : 기밀성 || 기밀성, 부인방지 및 인증
- 목적 : 데이터 암호화 || 키 교환
- 단점 : 별도의 키 교환 필요 || 공개키 중간자 공격에 취약
- 암호화 속도 : 빠름 || 느림
5. 전자서명
- 서명 : 누군가 문서를 기록했다는 증거 → 인증 및 부인방지 역할
1) 전자서명
- 원본 메시지에 대한 해시 값을 서명자의 개인키로 암호화하는 것
- 개인키로 암호화, 공개키로 복호화
- 메시지에 대한 인증, 부인방지 및 메시지 무결성 검증
2) 과정
- 원본 메시지에 해시 함수 적용 → 해시값 생성 → 송신자의 개인키로 해시값 서명 → 전자서명 생성
- 수신자는 받은 메시지에 해시 함수 적용, 전자서명을 송신자의 공개키로 검증하여 해시값끼리 비교
=> 해시값끼리 같으면 서명 인증이 가능함.
- 해시 함수 : 정보의 무결성을 확인하기 위한 목적으로 사용, 입력 메시지를 역으로 확인하는 것은 불가능함
3) 전자서명의 약점
- 송신자의 공개키가 맞는지 증명이 필요함
6. 공개키 기반 구조
1) 공개키 인증서(PKC)
- 사용자의 공개키와 신원정보를 묶어 인증기관이 보증한 전자문서
2) CA
- 공개키가 진짜 누구의 것인지 확인해주는 신뢰기관
=> 신뢰할 수 있는 인증기관(CA)을 이용하여 신뢰할 수 있는 안전한 공개키를 제공
3) PKI(공개키 기반 구조)
- 공개키를 효과적으로 사용하여 안전한 암호화와 전자서명 기능등을 제공하는 보안 환경
- ex) 인터넷뱅킹의 공인인증서
4) 구성요소
(1) 인증기관(CA)
- 인증정책 수립, 인증서 관리, 인증서 폐기 목록 등록/관리/인증, 공개키가 진짜인지 보증
(2) 등록기관(RA)
- 사용자 신원 확인, 인증서 요구 승인, CA에 인증서 발급 요청, 인터페이스 제공
(3) 검증기관(VA)
- 인증서 유효성 검증/확인 주체
(4) 인증서 폐기 목록(CRL)
- 폐기된 인증서 목록, 유출되거나 신뢰할 수 없는 인증서의 목록
(5) 디렉터리 서비스
- 인증서, 암호키에 대한 저장/검색/관리
(6) 인증서(X.509)
- CA가 발행한 공개키 인증서 표준 형식
인증서 발급과 검증 흐름
- 사용자 A → RA에 인증서 요청 → RA가 CA에 인증서 발급 요청 → CA가 인증서 발급 및 배포
- 사용자 A와 B의 거래 → 사용자 B가 디렉터리 서비스에서 인증서 확인
5) 인증서 사용방법
(1) 공개키 인증서
- 사용자의 공개키에 사용자의 식별 정보를 추가하여 만든 일종의 전자 신분증
Step 1 : 인증서 등록 및 배포 과정
- 밥이 개인키와 공개키 생성
- 밥이 인증기관에 자신의 공개키 등록
- 인증기관이 밥의 공개키와 정보 확인 후 인증서 작성
- 인증 기관이 인증서에 디지털 서명
=> 밥의 인증서에는 밥의 공개키 + 인증기관의 디지털 서명 정보가 들어감
Step 2 : 인증서 검증 및 공개키 사용
- 앨리스가 밥의 인증서를 받음
- 앨리스는 인증기관의 공개키로 인증서 서명을 검증
- 인증서가 정상이면 밥의 공개키를 신뢰
- 앨리스는 밥의 공개키로 메시지 암호화
- 밥은 자신의 개인키로 메시지 복호화
=> 밥의 공개키를 그냥 믿는 것이 아닌 인증기관의 서명을 인증기관의 공개키로 검증 후 신뢰함
(인증기관의 인증서는 인증 기관의 공개키와 상위 인증 기관의 서명 으로 이루어짐)
(2) 확인 과정의 상세 내용
- 인증서에 포함될 밥의 공개키와 신원 정보 등을 해시하여 Message Digest를 생성함
- 이를 CA의 개인키로 서명함
- 결국 밥의 공개키 인증서는 밥의 공개키, 신원 정보, CA의 전자서명으로 이루어짐
- 클라이언트는 인증서 안의 정보에 해시 함수를 적용하여 Message Digest를 생성함
- CA의 디지털 서명을 CA의 공개키로 검증하여 또 다른 Message Digest를 추출함
- 두 Message Digest를 비교하여 같으면 인증서가 변조되지 않았고, CA가 보증한 인증서임을 확인할 수 있음
=> 즉 사용자는 인증서를 받은 뒤 CA의 공개키로 서명을 검증하여 인증서가 진짜인지 확인함.
인증서 연결 구조
- 여기서의 의문점 : CA의 공개키는 믿을만 한가?
=> 인증서 연결 구조 등장(신뢰 체인)
- 검증 방법 : 인증서의 발급 기관 이름을 추적하여 상위 기관의 인증서를 찾음
- 그 후 발급자 서명과 상위 기관 인증서의 공개키를 이용해 인증서의 서명을 검증함
- 이 과정이 중간 CA를 거쳐 최상위 Root CA까지 이어짐
- 최상위 기관 : Root CA 기관 이름(Comodo, Godaddy 등), 자체 서명, Root CA 공개키, 인증서 해시값을 가짐ㆍ 서버 인증서는 이 루트 인증서에서 이어지는 체인에 포함되어야 신뢰됨
- ㆍ 브라우저나 운영체제가 미리 신뢰하고 있음
- 중간 기관 : 중간 CA 이름, 발급 기관 이름(Root CA), 공개키, 인증서 해시값, 발급자 서명을 가짐ㆍ 서버 인증서는 중간 CA의 개인키로 서명되어 있음
- ㆍ 중간 CA 인증서는 Root CA의 개인키로 서명되어 있음
=> 이처럼 인증서가 상위 인증기관의 서명으로 계속 연결되어 최종적으로 Root CA까지 이어지는 구조를 신뢰 체인이라고 함
6) 상호인증
- 두 인증기관이 상대방의 공개키를 서로 인증해주는 인증서를 발급하여 사용하는 것
- 상호 인증서
=> 서로 다른 인증기관끼리 상대방의 공개키를 신뢰할 수 있도록 인증서를 발급
5. 암호화 코드 실습
1) 대칭키
- 암호화 키 = 복호화 키
- 속도가 빠름
- but, 키 교환 문제, 송신가와 수신자가 같은 키를 가져야해서 안전하게 전달해야함
=> 전달 중 탈취되거나 노출될 위험 있음, 통신 상대 많아지면 키 관리가 복잡해짐
(1) cryptopgraphy 라이브러리의 Fernet 사용
pip install cryptography
from cryptography.fernet import Fernet
# 키 생성
key = Fernet.generate_key() # 대칭키 값 자체를 생성 ex ) key = b'abc123...'
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}") # 복호화된 평문 출력
(2) pycryptodome : AES
pip install pycryptodome
from Crypto.Cipher import AES # AES 암호화 기능 import
from Crypto.Random import get_random_bytes # 랜덤 바이트 생성 기능
# 암호화 키 생성
key = get_random_bytes(16) # AES 대칭키 값 자체를 16바이트로 생성 (16바이트 = 128비트 : AES-128 키)
# 암호화 객체 생성
cipher = AES.new(key, AES.MODE_EAX) # 암호화 객체 생성 (암호화와 무결성 검증을 같이 제공)
# 내부적으로 cipher.nonce가 자동 생성 (비밀값이 아닌 이번 암호문 작업에서 쓰이는 일회성 값으로 같이 전송함)
# 암호화할 데이터
data = b"Secret Message"
# 데이터 암호화
ciphertext, tag = cipher.encrypt_and_digest(data) # =암호화 결과로써 암호문과 인증태그 생성 (변조 여부 확인)
# 복호화 객체 생성
cipher_dec = AES.new(key, AES.MODE_EAX, cipher.nonce) # 암호화할때 사용한 nonce도 사용해야함
# 데이터 복호화
decrypted_data = cipher_dec.decrypt_and_verify(ciphertext, tag) #암호문을 복호화, tag로 변조여부 확인
print("Original:", data)
print("Decrypted:", decrypted_data)
2) 비대칭키
- 암호화 키 ≠ 복호화 키
- 공개키와 개인키를 각각 가지고 있고, 공개키는 공개키 저장소를 통해 모든 사람이 접근 가
- 키 분배와 관리가 편하지만, 키 길이가 길고 연산이 복잡해서 속도가 느림
- 기밀성, 무결성, 부인 방지 제공
pip install pynacl #PyNaCl 라이브러리 사용
from nacl.public import PrivateKey, Box
# 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) # 송신자의 개인키와, 수신자의 공개키로 암호화할 Box를 만듦
# 메시지 암호화
message = b"Hello PyNaCl"
encrypted = sender_box.encrypt(message)
# 수신자의 Box 생성
receiver_box = Box(receiver_sk, pk) # 수신자의 개인키와, 송신자의 공개키로 복호화할 Box 만듦
# 메시지 복호화
decrypted = receiver_box.decrypt(encrypted)
print("Encrypted message:", encrypted)
print("Decrypted message:", decrypted)
'보안' 카테고리의 다른 글
| 정보보안 14주차 - 보안 솔루션 (0) | 2026.06.11 |
|---|---|
| 정보보안 13주차 - 악성코드와 소프트웨어 보안 (0) | 2026.06.10 |
| 정보보안 10,11 주차 - 소켓 프로그래밍 (0) | 2026.06.01 |
| 정보보안 9주차 - 파이썬 기초 (0) | 2026.05.28 |