파이썬 실습/암호화프로그램만들기

파이썬 암호화 프로그램 만들기 - 3. 양방향 암호화 - 대칭키(비공개키) 방식

파기차차 2022. 11. 18. 09:40
728x90
반응형
SMALL
반응형
ㅁ 개요

 

O 프로그램 소개
 

 

 

 - 이번 프로그램은 이전글(2022.11.15 - [파이썬 실습/암호화프로그램만들기] - 파이썬 암호화 프로그램 만들기 - 2. 단방향 암호화)에 이은 3번째 글로 양방향 암호화 - 대칭키(비공개키) 방식에 대하여 설명합니다.

 

(본 블로그의 내용은 유튜브 동영상(

파이썬 암호화 프로그램 만들기-1.키생성(making Encryption program byPython 3. Symmetric key encryption-1.make key)

파이썬 암호화 프로그램 만들기-2.메시지암호화(Encryption program byPython 3. Symmetric key encryption-2.encrypt message)

파이썬 암호화 프로그램 만들기-3.메시지복호화(Encryption program byPython 3. Symmetric key encryption-3.decrypt message)

)에서 더욱 자세히 보실 수 있습니다.)

 

 

 

 

 - 대칭키 암호화 알고리즘으로는 DES, AES, SEED 등이 존재하나, 여기서는 가장 유명하고 널리 사용되는 AES를 기준으로  설명합니다.

 

 - 대칭키 암호화 방식의 가장 대표적인 AES암호화 알고리즘은 하나의 키로 암호화 및 복호화를 수행합니다. 그렇기 때문에 공개키에 비해 매우 빠르게 수행되는 장점이 있는 반면 키를 상대방에게 전달할때 해커들에게 가로채기 등을 당할 수 있어 키교환(키관리) 문제가 필연적으로 발생하게 됩니다.

(공개키가 생성된 배경에는 대칭키의 이러한 치명적인 단점으로 인해 공개키가 만들어 졌다고 보시면 되겠습니다.)

 

대칭키 방식에 대한  아주 쉬운 설명은 아래에서 들으실 수 있습니다.

(개인적으로 이 어려운 내용을 이렇게 쉽게 설명하는 곳은 처음 봤습니다. 제가 감동 받아서 이렇게 링크로 공유 드립니다.)

https://www.youtube.com/watch?v=0nPDwJPxOVQ (암호학1-3. 양방향 암호화 방식 - 대칭키 방식, 생활코딩)

 

 

 

 

 

O 완성된 프로그램 실행 화면
 

 

 - 최종 완성된 프로그램의 결과화면은 아래와 같습니다.

(1) 프로그램을 실행시키면 1. 키를 인코딩&해시한 후 2. 1에서 만든 키로 메시지를 AES 암호화 알고리즘 방식으로 암호화하고, 3.다시 암호화된 메시지를 동일한 키로 복호화 합니다.

아래 프로그램 실행 결과 메시지 원문을 암호화 한 후 복호화가 잘 된 것을 확인 할 수 있습니다.

 

 

 


 

O 시작전 준비 사항

 

 

 - 프로그램을 실행하기 위해서는 아래 모듈들이 필요합니다. 아래와 같이 임포트 해줍니다.

 

import base64
import hashlib
from Crypto.Cipher import AES # 대칭키를 사용하기 위한 모듈 임포트

 

 

***에러 발생시 조치 사항(에러가 없는 경우 안보셔도 됩니다.)

--------------------------------------------------------------------------------------

만일 아래와 같이 에러 발생 시

ModuleNotFoundError: No module named 'Crypto'

 

pip install pycrypto <-- 현재 이 모듈은 더 이상 안전하지 않아 설치 되지 않음
pip install pycryptodome <-- 이 모듈을 설치

 

 

위의 모듈 설치 후에도 계속 동일한 에러 발생 시

ModuleNotFoundError: No module named 'Crypto'


아래 부분을 에서 와 같이 수정
from Crypto.cipher import PKCS1_OAEP # 소문자를

 

이렇게 수정

from Crypto.Cipher import PKCS1_OAEP # 대문자로 수정

--------------------------------------------------------------------------------------

 

 

여기까지 이상없이 되셨다면 이제 우리는 다음 단계로 넘어갈 준비가 되었습니다.


 

ㅁ 세부 내용
 
O 완성된 소스

 

소스 1.make_AESkey.py : aes객체(키) 생성

 

 

# import base64
import hashlib
from Crypto.Cipher import AES # 대칭키를 사용하기 위한 모듈 임포트

class AESCipher(object):
    def __init__(self, key):
        self.key = hashlib.sha256(key.encode()).digest() # 키가 쉽게 노출되는 것을 막기 위해 키를 어렵게 처리하는 과정으로 보통 해시를 적용
        print("AES Key(Key문장 암호화) : ", self.key)


print("-"*100, "\n")
key = "aesKey"
msg = "원본 메시지 입니다."
print("AES KEY: ", key)
print("원본 메시지: ", msg)


aes = AESCipher(key) # 1. 대칭키 암복호화 처리를 위해 AESCipher클래스의 객체(인스턴스)를 생성(해시(256bit)가 적용된 키값을 얻어옴)
# print(aes)

 

 

 

소스 2.encrypt_msg.py : msg(메시지)를 AES 암호화 알고리즘 방식으로 암호화

 

import base64
import hashlib
from Crypto.Cipher import AES # 대칭키를 사용하기 위한 모듈 임포트


BS = 16 # blocksize를 16바이트로 고정시켜야 함(AES의 특징)

# AES에서는 블럭사이즈가 128bit 즉 16byte로 고정되어 있어야 하므로 문자열을 encrypt()함수 인자로 전달시
# 입력 받은 데이터의 길이가 블럭사이즈의 배수가 아닐때 아래와 같이 패딩을 해주어야 한다.
# 패딩: 데이터의 길이가 블럭사이즈의 배수가 아닐때 마지막 블록값을 추가해 블록사이즈의 배수로 맞추어 주는 행위
pad = (lambda s: s+ (BS - len(s) % BS) * chr(BS - len(s) % BS).encode())
unpad = (lambda s: s[:-ord(s[len(s)-1:])])

class AESCipher(object):
    def __init__(self, key):
        self.key = hashlib.sha256(key.encode()).digest() # 키가 쉽게 노출되는 것을 막기 위해 키를 어렵게 처리하는 과정으로 보통 해시를 적용
        print("AES Key(Key문장 암호화) : ", self.key)

    def encrypt(self, message): # 암호화 함수
        message = message.encode() # 문자열 인코딩
        raw = pad(message) # 인코딩된 문자열을 패딩처리
        cipher = AES.new(self.key, AES.MODE_CBC, self.__iv().encode('utf8')) # AES 암호화 알고리즘 처리(한글처리를 위해 encode('utf8') 적용)
        enc = cipher.encrypt(raw) # 패딩된 문자열을 AES 알고리즘으로 암호화
        return base64.b64encode(enc).decode('utf-8') # 암호화된 문자열을 base64 인코딩 후 리턴

    def __iv(self):
        return chr(0) * 16

print("-"*100, "\n")
key = "aesKey"
msg = "원본 메시지 입니다."
print("AES KEY: ", key)
print("원본 메시지: ", msg)

aes = AESCipher(key) # 1. 대칭키 암복호화 처리를 위해 AESCipher클래스의 객체(인스턴스)를 생성(해시(256bit)가 적용된 키값을 얻어옴)
# print(aes)

encrypt = aes.encrypt(msg) # 2.입력한 메시지를 AES 대칭키 암호화 방식으로 암호화
print("_"*100, "\n")
print("원본 메시지를 AES키로 암호화한 결과: ", encrypt)
print("_"*100, "\n")

 

 

 

 

 

소스 3.decrypt_msg.py : 암호화된 msg(메시지)를 다시 위에서 복호화

 

 

import base64
import hashlib
from Crypto.Cipher import AES # 대칭키를 사용하기 위한 모듈 임포트


BS = 16 # blocksize를 16바이트로 고정시켜야 함(AES의 특징)

# AES에서는 블럭사이즈가 128bit 즉 16byte로 고정되어 있어야 하므로 문자열을 encrypt()함수 인자로 전달시
# 입력 받은 데이터의 길이가 블럭사이즈의 배수가 아닐때 아래와 같이 패딩을 해주어야 한다.
# 패딩: 데이터의 길이가 블럭사이즈의 배수가 아닐때 마지막 블록값을 추가해 블록사이즈의 배수로 맞추어 주는 행위
pad = (lambda s: s+ (BS - len(s) % BS) * chr(BS - len(s) % BS).encode())
unpad = (lambda s: s[:-ord(s[len(s)-1:])])

class AESCipher(object):
    def __init__(self, key):
        self.key = hashlib.sha256(key.encode()).digest() # 키가 쉽게 노출되는 것을 막기 위해 키를 어렵게 처리하는 과정으로 보통 해시를 적용
        print("AES Key(Key문장 암호화) : ", self.key)

    def encrypt(self, message): # 암호화 함수
        message = message.encode() # 문자열 인코딩
        raw = pad(message) # 인코딩된 문자열을 패딩처리
        cipher = AES.new(self.key, AES.MODE_CBC, self.__iv().encode('utf8')) # AES 암호화 알고리즘 처리(한글처리를 위해 encode('utf8') 적용)
        enc = cipher.encrypt(raw) # 패딩된 문자열을 AES 알고리즘으로 암호화
        return base64.b64encode(enc).decode('utf-8') # 암호화된 문자열을 base64 인코딩 후 리턴

    def decrypt(self, enc): # 복호화 함수 -> 암호화의 역순으로 진행
        enc = base64.b64decode(enc) # 암호화된 문자열을 base64 디코딩 후
        cipher = AES.new(self.key, AES.MODE_CBC, self.__iv().encode('utf8')) # AES암호화 알고리즘 처리(한글처리를 위해 encode('utf8') 적용)
        dec = cipher.decrypt(enc) # base64 디코딩된 암호화 문자열을 복호화
        return unpad(dec).decode('utf-8') # 복호화된 문자열에서 패딩처리를 풀고(unpading) 리턴

    def __iv(self):
        return chr(0) * 16

print("-"*100, "\n")
key = "aesKey"
msg = "원본 메시지 입니다."
print("AES KEY: ", key)
print("원본 메시지: ", msg)


aes = AESCipher(key) # 1. 대칭키 암복호화 처리를 위해 AESCipher클래스의 객체(인스턴스)를 생성(해시(256bit)가 적용된 키값을 얻어옴)
# print(aes)

encrypt = aes.encrypt(msg) # 2.입력한 메시지를 AES 대칭키 암호화 방식으로 암호화
print("_"*100, "\n")
print("메시지 원본을 aes키로 암호화한 결과: ", encrypt)
print("_"*100, "\n")


decrypt = aes.decrypt(encrypt) # 3.암호화된 메시지를 AES 대칭키 암호화 방식으로 복호화
print("암호화된 메시지를 복호화한 결과: ", decrypt) 
print("_"*100, "\n")

 

 

 

 

O 소스 다운로드 및 실행
 
 - 소스파일 다운로드 후 cmd 또는 파워쉘 등에서 아래와 같이 실행하시기 바랍니다.
 
 
 > python 1.make_AESKey.py
 
 > python 2.encrypt_msg.py
  
 > python 3.decrypt_msg.py

 

 


 
 
O 소스 분석

 

1.from Crypto.Cipher import AES <-- 대칭키를 사용하기 위한 모듈 임포트
2.BS = 16 <-- blocksize를 16바이트로 고정시켜야 함(AES의 특징)

3.pad = (lambda s: s+ (BS - len(s) % BS) * chr(BS - len(s) % BS).encode()) <-- 패딩 처리
# AES에서는 블럭사이즈가 128bit 즉 16byte로 고정되어 있어야 하므로 문자열을 encrypt()함수 인자로 전달시
# 입력 받은 데이터의 길이가 블럭사이즈의 배수가 아닐때 아래와 같이 패딩을 해주어야 한다.
# 패딩: 데이터의 길이가 블럭사이즈의 배수가 아닐때 마지막 블록값을 추가해 블록사이즈의 배수로 맞추어 주는 행위

4.self.key = hashlib.sha256(key.encode()).digest() <-- 키가 쉽게 노출되는 것을 막기 위해 키를 어렵게 처리하는 과정으로 보통 해시를 적용
5.message = message.encode() <-- 문자열 인코딩
6.raw = pad(message) <-- 인코딩된 문자열을 패딩처리
7.cipher = AES.new(self.key, AES.MODE_CBC, self.__iv().encode('utf8')) <-- AES 암호화 알고리즘 처리(한글처리를 위해 encode('utf8') 적용)
8.enc = cipher.encrypt(raw) <-- 패딩된 문자열을 AES 알고리즘으로 암호화
9.return base64.b64encode(enc).decode('utf-8') <-- 암호화된 문자열을 base64 인코딩 후 리턴
10.enc = base64.b64decode(enc) <-- 암호화된 문자열을 base64 디코딩 후
11.cipher = AES.new(self.key, AES.MODE_CBC, self.__iv().encode('utf8')) <-- AES암호화 알고리즘 처리(한글처리를 위해 encode('utf8') 적용)
12.dec = cipher.decrypt(enc) <-- base64 디코딩된 암호화 문자열을 복호화
13.return unpad(dec).decode('utf-8') <-- 복호화된 문자열에서 패딩처리를 풀고(unpading) 리턴
14.aes = AESCipher(key) <-- 1. 대칭키 암복호화 처리를 위해 AESCipher클래스의 객체(인스턴스)를 생성(해시(256bit)가 적용된 키값을 얻어옴)
15.encrypt = aes.encrypt(msg) <-- 2.입력한 메시지를 AES 대칭키 암호화 방식으로 암호화
16.decrypt = aes.decrypt(encrypt) <-- 3.암호화된 메시지를 AES 대칭키 암호화 방식으로 복호화


 

O 주요 내용

 

 

소스 1.make_AESkey.py : aes객체 생성

 

1.기본 소스에 대한 설명은 위에서 설명 드린 바와 같으며, '1.make_AESkey.py' 소스 실행시 아래와 같이 AESCipher()클래스의 인스턴스를 생성하며, 초기화 함수(__init__() )에서 키가 쉽게 노출되는 것을 막기 위해 해시처리를 해줍니다.

 

 

소스 실행 결과 해시처리된 키가 잘 생성된 것을 확인 할 수 있습니다.

 

 

 


소스 2.encrypt_msg.py : msg(메시지)를 AES 암호화 알고리즘 방식으로 암호화

 

 

2. '2.encrypt_msg.py' 소스 실행시 아래와 같이 입력한 메시지를 AES대칭키 암호화 방식으로 암호화 처리(encrypt = aes.encrypt(msg))를 해줍니다.

encrypt()함수는 입력된 문자열을 AES 암호화 알고리즘의 특성에 맞게 패딩처리를 해주고, AES 암호화 알고리즘을 적용한 뒤, 패딩처리된 문자열을 AES 알고리즘으로 암호화합니다.

(위 내용이 조금 어렵습니다. 아래 소스에 주석을 달아 놓았으니, 여러번 천천히 반복해서 보시기 바랍니다.)

 

 

 

소스 실행 결과 입력된 메시지를 AES 암호화 방식으로 잘 암호화 된 것을 확인 할 수 있습니다.

 

 

 


소스 3.decrypt_msg.py : 암호화된 msg(메시지)를 다시 위에서 복호화

 

3. '3.decrypt_msg.py' 소스 실행시 아래와 같이 입력한 메시지를 AES대칭키 암호화 방식의 역순으로 복호화 처리(decrypt = aes.decrypt(encrypt))를 해줍니다.

decrypt()함수는 암호화된 문자열을 base64 디코딩 후 AES 암호화 알고리즘을 적용한 뒤, base64 디코딩된 문자열을 복호화 해줍니다.

(마찬가지로 위 내용이 조금 어렵습니다. 아래 소스에 주석을 달아 놓았으니, 여러번 천천히 반복해서 보시기 바랍니다.)

 

 

소스 실행 결과 암호화된 메시지를 AES 암호화 알고리즘 방식으로 잘 복호화 된 것을 확인 할 수 있습니다.

 


 

ㅁ 정리
 
O 우리가 배운 내용
 
 - 오늘은 암호화의 내용 중 양방향 암호화 - 비공개키(대칭키) 암호화 방식에 대하여 공부해 보았습니다.

 

 
 
 - 오늘 우리가 배운 내용을 간단히 정리해 보면 아래와 같습니다.
 
 > 1. 객체(키)생성 : 키 인코딩 및 해시, 소스 1.make_AESKey.py
 > 2. 메시지 암호화 : 위에서 만든키로 msg(메시지)를 AES 암호화 알고리즘 방식으로 암호화 , 소스 2.encrypt_msg.py 
 > 3. 메시지 복호화: 암호화된 msg(메시지)를 다시 위에서 만든 동일한 키로 복호화, 소스 3.decrypt_msg.py
 
 

 

오늘은 여기까지이며, 위의 내용이 유익하셨다면, 좋아요와 구독 부탁드립니다.

 

 

감사합니다.

 

 

 

728x90
반응형
LIST